diff -u --recursive --new-file v2.3.42/linux/CREDITS linux/CREDITS --- v2.3.42/linux/CREDITS Tue Feb 1 01:35:43 2000 +++ linux/CREDITS Thu Feb 10 12:28:01 2000 @@ -24,6 +24,12 @@ S: Iasi 6600 S: Romania +N: Monalisa Agrawal +E: magrawal@nortelnetworks.com +D: Basic Interphase 5575 driver with UBR and ABR support. +S: 75 Donald St, Apt 42 +S: Weymouth, MA 02188 + N: Dave Airlie E: airlied@linux.ie W: http://www.csn.ul.ie/~airlied @@ -38,11 +44,11 @@ S: United Kingdom N: Werner Almesberger -E: werner.almesberger@lrc.di.epfl.ch -D: dosfs, LILO, some fd features, various other hacks here and there +E: werner.almesberger@epfl.ch +D: dosfs, LILO, some fd features, ATM, various other hacks here and there S: Ecole Polytechnique Federale de Lausanne -S: DI-LRC -S: INR (Ecublens) +S: DSC ICA +S: INN (Ecublens) S: CH-1015 Lausanne S: Switzerland @@ -155,6 +161,14 @@ S: Notre Dame, Indiana S: USA +N: Greg Banks +E: gnb@linuxfan.com +D: IDT77105 ATM network driver +S: NEC Australia +S: 649-655 Springvale Rd +S: Mulgrave, Victoria 3170 +S: Australia + N: James Banks E: james@sovereign.org D: TLAN network driver @@ -461,6 +475,13 @@ S: NN1 3QT S: United Kingdom +N: Uwe Dannowski +E: Uwe.Dannowski@ira.uka.de +W: http://i30www.ira.uka.de/~dannowsk/ +D: FORE PCA-200E driver +S: University of Karlsruhe +S: Germany + N: Ray Dassen E: jdassen@wi.LeidenUniv.nl W: http://www.wi.leidenuniv.nl/~jdassen/ @@ -521,11 +542,11 @@ S: Belgium N: Cort Dougan -E: cort@ppc.kernel.org +E: cort@fsmlabs.com W: http://www.ppc.kernel.org/~cort/ D: PowerPC -S: Computer Science Department -S: New Mexico Tech +S: Finite State Machine Labs +S: P.O. 1829 S: Socorro, New Mexico 87801 S: USA @@ -538,6 +559,20 @@ S: Crimea S: UKRAINE, 334320 +N: Walt Drummond +E: drummond@valinux.com +D: Linux/IA-64 +S: 1382 Bordeaux Drive +S: Sunnyvale, CA 94087 +S: USA + +N: Don Dugger +E: n0ano@valinux.com +D: Linux/IA-64 +S: 1209 Pearl Street, #12 +S: Boulder, CO 80302 +S: USA + N: Thomas Dunbar E: tdunbar@vtaix.cc.vt.edu D: TeX & METAFONT hacking/maintenance @@ -602,6 +637,13 @@ S: S-114 53 Stockholm S: Sweden +N: Stephane Eranian +E: eranian@hpl.hp.com +D: Linux/ia64 +S: 1501 Page Mill Rd, MS 1U17 +S: Palo Alto, CA 94304 +S: USA + N: Paal-Kristian Engstad E: engstad@intermetrics.com D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.) @@ -609,6 +651,13 @@ S: Huntington Beach, California 92649 S: USA +N: Johannes Erdfelt +E: jerdfelt@valinux.com +D: Linux/IA-64 bootloader and kernel goop, USB +S: 6350 Stoneridge Mall Road +S: Pleasanton, CA 94588 +S: USA + N: Doug Evans E: dje@cygnus.com D: Wrote Xenix FS (part of standard kernel since 0.99.15) @@ -883,6 +932,7 @@ E: benh@mipsys.com D: PowerMac booter (BootX) D: Additional PowerBook support +D: Apple "Core99" machines support (ibook,g4,...) S: 22, rue des Marguettes S: 75012 Paris S: France @@ -1123,6 +1173,13 @@ S: TW9 1AE S: United Kingdom +N: Marko Kiiskila +E: marko@iprg.nokia.com +D: Author of ATM Lan Emulation +S: 660 Harvard Ave. #7 +S: Santa Clara, CA 95051 +S: USA + N: Russell King E: rmk@arm.uk.linux.org D: Linux/arm integrator, maintainer & hacker @@ -1321,6 +1378,15 @@ S: (ask for current address) S: Germany +N: Christophe Lizzi +E: lizzi@cnam.fr +W: http://cedric.cnam.fr/personne/lizzi +D: FORE Systems 200E-series ATM network driver, sparc64 port of ATM +S: CNAM, Laboratoire CEDRIC +S: 292, rue St-Martin +S: 75141 Paris Cedex 03 +S: France + N: Siegfried "Frieder" Loeffler (dg1sek) E: floeff@tunix.mathematik.uni-stuttgart.de, fl@LF.net W: http://www.mathematik.uni-stuttgart.de/~floeff @@ -1418,6 +1484,13 @@ E: Kai.Makisara@metla.fi D: SCSI Tape Driver +N: Asit Mallick +E: asit.k.mallick@intel.com +D: Linux/IA-64 +S: 2200 Mission College Blvd +S: Santa Clara, CA 95052 +S: USA + N: Martin Mares E: mj@atrey.karlin.mff.cuni.cz W: http://atrey.karlin.mff.cuni.cz/~mj/ @@ -1759,6 +1832,11 @@ S: 13349 Berlin S: Germany +N: Nicolas Pitre +E: nico@cam.org +D: StrongARM SA1100 support integrator & hacker +S: Montreal, Quebec, Canada + N: Emanuel Pirker E: epirker@edu.uni-klu.ac.at D: AIC5800 IEEE 1394, RAW I/O on 1394 @@ -1773,6 +1851,10 @@ E: Frederic.Potter@masi.ibp.fr D: Some PCI kernel support +N: Rui Prior +E: rprior@inescn.pt +D: ATM device driver for NICStAR based cards + N: Stefan Probst E: sp@caldera.de D: The Linux Support Team Erlangen, 1993-97 @@ -1799,6 +1881,13 @@ S: 89020-350 Blumenau - Santa Catarina S: Brazil +N: Goutham Rao +E: goutham.rao@intel.com +D: Linux/IA-64 +S: 2200 Mission College Blvd +S: Santa Clara, CA 95052 +S: USA + N: Eric S. Raymond E: esr@thyrsus.com W: http://www.tuxedo.org/~esr/ @@ -1893,11 +1982,10 @@ D: the gpm mouse server and kernel support for it N: Philipp Rumpf -E: prumpf@jcsbs.lanobis.de -D: ipi_count for x86 +E: prumpf@tux.org D: random bugfixes -S: Rueting 4 -S: 23743 Groemitz +S: Drausnickstrasse 29 +S: 91052 Erlangen S: Germany N: Paul `Rusty' Russell @@ -2053,6 +2141,15 @@ S: Cliffwood, New Jersey 07721 S: USA +N: Manfred Spraul +E: manfreds@colorfullife.com +W: http://colorfullife.com/~manfreds +D: major SysV IPC changes +D: various bug fixes (mostly SMP code) +S: Warburgring 67 +S: 66424 Homburg +S: Germany + N: Henrik Storner E: storner@image.dk W: http://www.image.dk/~storner/ @@ -2348,6 +2445,13 @@ S: Berkeley, CA 94720-1776 S: USA +N: Mike Westall +D: IBM Turboways 25 ATM Device Driver +E: westall@cs.clemson.edu +S: Department of Computer Science +S: Clemson University +S: Clemson SC 29634 USA + N: Greg Wettstein E: greg@wind.rmcc.com D: Filesystem valid flag for MINIX filesystem. @@ -2509,6 +2613,20 @@ S: 3078 Sulphur Spring Court S: San Jose, California 95148 S: USA + +N: Alessandro Zummo +E: azummo@ita.flashnet.it +W: http://freepage.logicom.it/azummo/ +D: CMI8330 support is sb_card.c +D: ISAPnP fixes in sb_card.c +S: Italy + +N: Alessandro Zummo +E: azummo@ita.flashnet.it +W: http://freepage.logicom.it/azummo/ +D: CMI8330 support is sb_card.c +D: ISAPnP fixes in sb_card.c +S: Italy N: Marc Zyngier E: maz@wild-wind.fr.eu.org diff -u --recursive --new-file v2.3.42/linux/Documentation/00-INDEX linux/Documentation/00-INDEX --- v2.3.42/linux/Documentation/00-INDEX Tue Dec 7 09:32:38 1999 +++ linux/Documentation/00-INDEX Tue Feb 8 11:28:31 2000 @@ -23,8 +23,6 @@ - info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux VGA-softcursor.txt - how to change your VGA cursor from a blinking underscore. -acpi.txt - - info on ACPI Driver Interface arm/ - directory with info about Linux on the ARM architecture. atm.txt @@ -125,6 +123,8 @@ - info on the PCI subsystem for device driver authors pcwd-watchdog.txt - info and sample code for using with the PC Watchdog reset card. +pm.txt + - info on Linux power management support powerpc/ - directory with info on using Linux with the PowerPC. proc_usb_info.txt diff -u --recursive --new-file v2.3.42/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.42/linux/Documentation/Configure.help Tue Feb 1 01:35:43 2000 +++ linux/Documentation/Configure.help Thu Feb 10 12:28:01 2000 @@ -557,6 +557,13 @@ People with SCSI-only systems should say N here. If unsure, say Y. +Cyrix CS5530 MediaGX chipset support +CONFIG_BLK_DEV_CS5530 + Include support for UDMA on the Cyrix MediaGX 5530 chipset. This + will automatically be detected and configured if found. + + It is safe to say Y to this question. + Generic PCI IDE chipset support CONFIG_BLK_DEV_IDEPCI Say Y here for PCI systems which use IDE drive(s). @@ -583,7 +590,7 @@ It is safe to say Y to this question. Good-Bad DMA Model-Firmware (EXPERIMENTAL) -IDEDMA_NEW_DRIVE_LISTINGS +CONFIG_IDEDMA_NEW_DRIVE_LISTINGS If you say Y here, the model and firmware revision of your drive will be compared against a blacklist of buggy drives that claim to be (U)DMA capable but aren't. This is a blanket on/off test with no @@ -711,12 +718,12 @@ Please read the comments at the top of drivers/block/hpt366.c HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP) -HPT366_FAST_IRQ_PREDICTION +CONFIG_HPT366_FAST_IRQ_PREDICTION If unsure, say N. HPT366 mode three unsupported (EXPERIMENTAL) (WIP) -HPT366_MODE3 +CONFIG_HPT366_MODE3 This is an undocumented mode that the HA366 can default to in many cases. If unsure, say N. @@ -785,7 +792,7 @@ If unsure, say N. Special UDMA Feature -PDC202XX_FORCE_BURST_BIT +CONFIG_PDC202XX_FORCE_BURST_BIT For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally for PDC20246/Ultra33 that has BIOS setup failures when using 3 or more cards. @@ -795,7 +802,7 @@ If unsure, say N. Special Mode Feature (EXPERIMENTAL) -PDC202XX_FORCE_MASTER_MODE +CONFIG_PDC202XX_FORCE_MASTER_MODE For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for possible Hardware RAID 0,1 for the FastTrak Series. @@ -2171,7 +2178,8 @@ Acorn VIDC support CONFIG_FB_ACORN This is the frame buffer device driver for the Acorn VIDC graphics - chipset. + hardware found in Acorn RISC PCs and other ARM-based machines. If + unsure, say N. Apollo frame buffer device CONFIG_FB_APOLLO @@ -2212,6 +2220,13 @@ kernel. Please note that this driver DOES NOT support the Cybervision 64 3D card, as they use incompatible video chips. +CyberPro 20x0 support +CONFIG_FB_CYBER2000 + This enables support for the Integraphics CyberPro 20x0 and 5000 + VGA chips used in the Rebel.com Netwinder and other machines. + Say Y if you have a NetWinder or a graphics card containing this + device, otherwise say N. + Amiga CyberVision3D support (EXPERIMENTAL) CONFIG_FB_VIRGE This enables support for the Cybervision 64/3D graphics card from @@ -2332,6 +2347,14 @@ You will get a boot time penguin logo at no additional cost. Please read Documentation/fb/vesafb.txt. If unsure, say Y. +VGA 16-color planar support +CONFIG_FBCON_VGA_PLANES + This low level frame buffer console driver enable the kernel to use + the 16-color planar modes of the old VGA cards where the bits of each + pixel are separated into 4 plans. + Only answer Y here if you have an (very old) VGA card that isn't + VESA 2 compatible. + VGA 16-color graphics console CONFIG_FB_VGA16 This is the frame buffer device driver for VGA 16 color graphic @@ -2342,6 +2365,25 @@ running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called vga16fb.o. +VGA 8x16 font +CONFIG_FONT_8x16 + This is the "high resolution" font for the VGA frame buffer (the one + provided by the text console 80x25 mode. + +Support only 8 pixels wide fonts +CONFIG_FBCON_FONTWIDTH8_ONLY + Answer Y here will make the kernel provide only the 8x8 fonts (these + are the less readable). + +VGA 8x8 font +CONFIG_FONT_8x8 + This is the "high resolution" font for the VGA frame buffer (the one + provided by the text console 80x50 (and higher) modes. + Note this is a poor quality font. The VGA 8x16 font is quite a lot + more readable. + Given the resolution provided by the frame buffer device, anwser N + here is safe. + Backward compatibility mode for Xpmac CONFIG_FB_COMPAT_XPMAC If you use the Xpmac X server (common with mklinux), you'll need to @@ -2635,6 +2677,12 @@ Ultra/AX machines. This code is also available as a module (say M), called parport_ax.o. If in doubt, saying N is the safe plan. +Support IEEE1284 status readback +CONFIG_PRINTER_READBACK + If you have a device on your parrallel port that support this protocol, + this option'll enable it to report its status. + It is safe to say Y. + IEEE1284 transfer modes CONFIG_PARPORT_1284 If you have a printer that supports status readback or device ID, or @@ -3839,7 +3887,8 @@ of your ATM card below. Note that you need a set of user-space programs to actually make use - of ATM. See the file Documentation/atm.txt for further details. + of ATM. See the file Documentation/networking/atm.txt for further + details. Classical IP over ATM CONFIG_ATM_CLIP @@ -3981,12 +4030,30 @@ overhead for timer synchronization and also per-packet overhead for time conversion. -IDT 77201 (NICStAR) +IDT 77201/11 (NICStAR) (ForeRunnerLE) CONFIG_ATM_NICSTAR The NICStAR chipset family is used in a large number of ATM NICs for 25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE series. +ForeRunner LE155 PHYsical layer +CONFIG_ATM_NICSTAR_USE_SUNI + Support for the S-UNI and compatible PHYsical layer chips. These are + found in most 155Mbps NICStAR based ATM cards, namely in the + ForeRunner LE155 cards. This driver provides detection of cable + removal and reinsertion and provides some statistics. This driver + doesn't have removal capability when compiled as a module, so if you + need that capability don't include S-UNI support (it's not needed to + make the card work). + +ForeRunner LE25 PHYsical layer +CONFIG_ATM_NICSTAR_USE_IDT77105 + Support for the PHYsical layer chip in ForeRunner LE25 cards. In + addition to cable removal/reinsertion detection, this driver allows + you to control the loopback mode of the chip via a dedicated IOCTL. + This driver is required for proper handling of temporary carrier + loss, so if you have a 25Mbps NICStAR based ATM card you must say Y. + Madge Ambassador (Collage PCI 155 Server) CONFIG_ATM_AMBASSADOR This is a driver for ATMizer based ATM card produced by Madge @@ -4025,6 +4092,33 @@ speed of the driver, and the size of your syslog files! When inactive, they will have only a modest impact on performance. +Interphase ATM PCI x575/x525/x531 +CONFIG_ATM_IA + This is a driver for the Interphase (i)ChipSAR adapter cards + which include a variety of variants in term of the size of the + control memory (128K-1KVC, 512K-4KVC), the size of the packet + memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3, + UTP155, UTP25, DS3 and E3). Go to: + www.iphase.com/products/ClassSheet.cfm?ClassID=ATM + for more info about the cards. Say Y (or M to compile as a module + named iphase.o) here if you have one of these cards. + + See the file Documentation/networking/iphase.txt for further + details. + +Enable debugging messages +CONFIG_ATM_IA_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (Get the debug utility, iadbg, from + ftp.iphase.com/pub/atm/pci). See the file drivers/atm/iphase.h + for the meanings of the bits in the mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + SCSI support? CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or @@ -4067,6 +4161,18 @@ on a SCSI disk. In this case, do not compile the driver for your SCSI host adapter (below) as a module either. +Extra SCSI Disks +CONFIG_SD_EXTRA_DEVS + This controls the amount of additional space allocated in tables for + drivers that are loaded as modules after the kernel is booted. In + the event that the SCSI core itself was loaded as a module, this this + value is the number of additional disks that can be loaded after the + first host driver is loaded. + + Admittedly this isn't pretty, but there are tons of race conditions + involved with resizing the internal arrays on the fly. Someday this + flag will go away, and everything will work automatically. + SCSI tape support CONFIG_CHR_DEV_ST If you want to use a SCSI tape drive under Linux, say Y and read the @@ -4081,6 +4187,18 @@ module, say M here and read Documentation/modules.txt and Documentation/scsi.txt . +Extra SCSI Tapes +CONFIG_ST_EXTRA_DEVS + This controls the amount of additional space allocated in tables for + drivers that are loaded as modules after the kernel is booted. In the + event that the SCSI core itself was loaded as a module, this this value + is the number of additional tape devices that can be loaded after the + first host driver is loaded. + + Admittedly this isn't pretty, but there are tons of race conditions + involved with resizing the internal arrays on the fly. Someday this + flag will go away, and everything will work automatically. + SCSI CDROM support CONFIG_BLK_DEV_SR If you want to use a SCSI CDROM under Linux, say Y and read the @@ -4094,6 +4212,18 @@ module, say M here and read Documentation/modules.txt and Documentation/scsi.txt . +Extra SCSI CDROMs +CONFIG_SR_EXTRA_DEVS + This controls the amount of additional space allocated in tables for + drivers that are loaded as modules after the kernel is booted. In the + event that the SCSI core itself was loaded as a module, this this value + is the number of additional CDROMs that can be loaded after the first + host driver is loaded. + + Admittedly this isn't pretty, but there are tons of race conditions + involved with resizing the internal arrays on the fly. Someday this + flag will go away, and everything will work automatically. + Enable vendor-specific extensions (for SCSI CDROM) CONFIG_BLK_DEV_SR_VENDOR This enables the usage of vendor specific SCSI commands. This is @@ -7265,7 +7395,7 @@ Documentation/networking/net-modules.txt. DECchip Tulip (dc21x4x) PCI support -CONFIG_DEC_ELCP +CONFIG_TULIP This driver is developed for the SMC EtherPower series Ethernet cards and also works with cards based on the DECchip 21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are @@ -9398,9 +9528,9 @@ from the Microsoft fat filesystem family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 8 character - set, which adds the last accented vowels for Welsh (and Manx Gaelic) - that were missing in Latin 1. http://linux.speech.cymru.org/ - has further information. + set, which adds the last accented vowels for Welsh (aka Cymraeg) + (and Manx Gaelic) hat were missing in Latin 1. + http://linux.speech.cymru.org/ has further information. nls iso8859-15 CONFIG_NLS_ISO8859_15 @@ -10357,6 +10487,11 @@ If unsure, say N. +Enter S1 for sleep (EXPERIMENTAL) +CONFIG_ACPI_S1_SLEEP + This enable ACPI compliant devices to enter level 1 of ACPI saving + power levels. Basically, this will let them entering in sleep mode. + Advanced Power Management CONFIG_APM APM is a BIOS specification for saving power using several different @@ -12958,7 +13093,84 @@ If you do not have any Quicknet telephony cards, you can safely ignore this option. - + +/dev/agpgart (AGP Support) (EXPERIMENTAL) +CONFIG_AGP + The agpgart kernel module is necessary to use the AGP features + of your 3D rendering video card. It acts as a sort of "AGP + driver" for the motherboard's chipset. + Loading this module into the kernel will allow the glx module to + program the GART (graphics aperture relocation table) registers + with appropriate values to transfer commands to the card. + + If you need more texture memory than you can get with the AGP GART + (theoretically up to 256 megs, but in practice usually 64 or 128 + megs due to kernel allocation issues), you could use PCI accesses + and have up to a couple gigs of texture space. + + Note that this is the only meas to have get XFree4/GLX use + write-combining with MTRR support on AGP bus. Without, OpenGL + direct rendering will be a lot slower but still faster than PIO. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + + or need to use the 810 Xserver in XFree 3.3.6 + +Intel 440LX/BX/GX support +CONFIG_AGP_INTEL + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on Intel 440LX/BX/GX chipsets. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + +Intel I810/I810 DC100/I810e support +CONFIG_AGP_I810 + This option give you AGP support for the Xserver for the intel + 810 chipset boards. This is required to do any useful video + modes. + +VIA VP3/MVP3/Apollo Pro support +CONFIG_AGP_VIA + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on VIA MPV3/Apollo Pro chipsets. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + +AMD Irongate support +CONFIG_AGP_AMD + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on Intel AMD Irongate chipset. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + +Generic SiS support +CONFIG_AGP_SIS + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on Silicon Integrated Systems [SiS] + chipsets. + + Note than 5591/5592 AGP chipsets are NOT supported. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ + +ALI M1541 support +CONFIG_AGP_ALI + This option give you AGP support for the GLX component of the + "soon to be released" XFree86-4 on ALI M1541 chipset. + + For the moment, most people should say no, unless you want to + test the GLX component which can be downloaded from + http://glx.on.openprojects.net/ # # ARM options @@ -13487,7 +13699,6 @@ The kHTTPd is experimental. Be careful when using it on a production machine. Also note that kHTTPd doesn't support virtual servers yet. -# I2C support CONFIG_I2C I2C (pronounce: I-square-C) is a slow bus protocol developed by @@ -13540,6 +13751,7 @@ files, usually found in the /dev directory on your system. They make it possible to have user-space programs use the I2C bus. +# # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, # Intel, IRQ, Linux, MSDOS, NetWare, NetWinder, NFS, @@ -13801,4 +14013,4 @@ # LocalWords: adbmouse DRI DRM dlabs GMX PLCs Applicom fieldbus applicom int # LocalWords: VWSND eg ESSSOLO CFU CFNR scribed eiconctrl eicon hylafax KFPU # LocalWords: EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator -# LocalWords: LOGIBUSMOUSE OV511 ov511 +# LocalWords: LOGIBUSMOUSE OV511 ov511 Integraphics diff -u --recursive --new-file v2.3.42/linux/Documentation/acpi.txt linux/Documentation/acpi.txt --- v2.3.42/linux/Documentation/acpi.txt Thu Nov 11 20:11:30 1999 +++ linux/Documentation/acpi.txt Wed Dec 31 16:00:00 1969 @@ -1,125 +0,0 @@ -ACPI Driver Interface ---------------------- - -Overview: -1) Register each instance of a device with "acpi_register" -2) Call "acpi_access" before accessing the hardware. - (this will ensure that the hardware is awake and ready) -3) "acpi_transition" callback is called before entering D1-D3 - or after entering D0 -4) Call "acpi_dev_idle" when the device is not being used - (not required by will improve idle detection) -5) When unloaded, unregister the device with "acpi_unregister" - -/* - * Description: Register a device with the ACPI subsystem - * - * Parameters: - * info - static device information - * type - device type - * hid - PnP identifier (or 0 if unknown) - * trans - device state transition callback - * adr - bus number and address or unique id - * - * Returns: Registered ACPI device or NULL on error - * - * Details: The device type, bus number, and bus address should be - * enough information to reconstruct the device tree and - * identify device dependencies - * - * Examples: - * struct acpi_dev_info info = {ACPI_SYS_DEV, ACPI_VGA_HID, vga_trans}; - * dev = acpi_register(&info, 0); - * - * struct pci_dev *pci_dev = pci_find_dev(...); - * struct acpi_dev_info info = {ACPI_PCI_DEV, 0, trans}; - * dev = acpi_register(&info, ACPI_PCI_ADR(pci_dev)); - */ -struct acpi_dev *acpi_register(struct acpi_dev_info *info, unsigned long adr); - -/* - * Description: Unregister a device with ACPI - * - * Parameters: - * dev - ACPI device previously returned from acpi_register - */ -void acpi_unregister(struct acpi_dev *dev); - -/* - * Device idle/use detection - * - * In general, drivers for all devices should call "acpi_access" - * before accessing the hardware (ie. before reading or modifying - * a hardware register). Request or packet-driven drivers should - * additionally call "acpi_idle" when a device is not being used. - * - * Examples: - * 1) A keyboard driver would call acpi_access whenever a key is pressed - * 2) A network driver would call acpi_access before submitting - * a packet for transmit or receive and acpi_idle when its - * transfer and receive queues are empty. - * 3) A VGA driver would call acpi_access before it accesses any - * of the video controller registers - * - * Ultimately, the ACPI policy manager uses the access and idle - * information to decide when to transition devices between - * device states. - */ - -/* - * Description: Update device access time and wake up device, if necessary - * - * Parameters: - * dev - ACPI device previously returned from acpi_register - * - * Details: If called from an interrupt handler acpi_access updates - * access time but should never need to wake up the device - * (if device is generating interrupts, it should be awake - * already) This is important as we can not wake up - * devices (run AML, etc.) from an interrupt handler. - */ -void acpi_access(struct acpi_dev *dev); - -/* - * Description: Identify device as currently being idle - * - * Parameters: - * dev - ACPI device previously returned from acpi_register - * - * Details: A call to acpi_idle might signal to the policy manager - * to put a device to sleep. If a new device request arrives - * between the call to acpi_idle and the acpi_transition - * callback, the driver should fail the acpi_transition request. - */ -void acpi_dev_idle(struct acpi_dev *dev); - -/* - * Transition function - * - * Parameters: - * dev - ACPI device previously returned from acpi_register - * state - the device state being entered - * - * Returns: 0 if the state transition is possible and context saved - * EINVAL if the requested device state is not supported - * EBUSY if the device is now busy and can not transition - * ENOMEM if the device was unable to save context (out of memory) - * - * Details: The device state transition function will be called - * before the device is transitioned into the D1-D3 states - * or after the device is transitioned into the D0 state. - * The device driver should save (D1-D3) or restore (D0) - * device context when the transition function is called. - * - * For system devices, the ACPI subsystem will perform - * the actual hardware state transition itself. For bus - * devices, after the driver's acpi_transition function - * is called, the bus driver's acpi_transition function - * is called to perform the actual hardware state transition. - * - * Once a driver returns 0 (success) from a transition - * to D1-3 request, it should not process any further - * requests or access the device hardware until a - * call to "acpi_access" is made. - */ -typedef int (*acpi_transition)(struct acpi_dev *dev, acpi_dstate_t state); diff -u --recursive --new-file v2.3.42/linux/Documentation/arm/SA1100/Brutus linux/Documentation/arm/SA1100/Brutus --- v2.3.42/linux/Documentation/arm/SA1100/Brutus Fri Oct 22 13:21:43 1999 +++ linux/Documentation/arm/SA1100/Brutus Sun Feb 6 17:45:25 2000 @@ -16,7 +16,8 @@ 0xc0008000 as well. But prior to execute the kernel, a ramdisk image must also be loaded in -memory. Use memory address 0x00800000 for this. +memory. Use memory address 0xd8000000 for this. Note that the file +containing the (compressed) ramdisk image must not exceed 4 MB. Currently supported: - RS232 serial ports @@ -24,6 +25,10 @@ - LCD screen - keyboard (needs to be cleaned up badly... any volunteer?) +The actual Brutus support may not be complete without extra patches. +If such patches exist, they should be found from +ftp.netwinder.org/users/n/nico. + A full PCMCIA support is still missing, although it's possible to hack some drivers in order to drive already inserted cards at boot time with little modifications. diff -u --recursive --new-file v2.3.42/linux/Documentation/arm/nwfpe/README linux/Documentation/arm/nwfpe/README --- v2.3.42/linux/Documentation/arm/nwfpe/README Fri Oct 22 13:21:43 1999 +++ linux/Documentation/arm/nwfpe/README Sun Feb 6 17:45:25 2000 @@ -35,7 +35,7 @@ remains to be done, and other ideas for the emulator. Bug reports, comments, suggestions should be directed to me at -. General reports of "this program doesn't +. General reports of "this program doesn't work correctly when your emulator is installed" are useful for determining that bugs still exist; but are virtually useless when attempting to isolate the problem. Please report them, but don't diff -u --recursive --new-file v2.3.42/linux/Documentation/atm.txt linux/Documentation/atm.txt --- v2.3.42/linux/Documentation/atm.txt Fri Sep 10 23:57:27 1999 +++ linux/Documentation/atm.txt Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -In order to use anything but the most primitive functions of ATM, -several user-mode programs are required to assist the kernel. These -programs and related material can be found via the ATM on Linux Web -page at http://icawww1.epfl.ch/linux-atm/ - -If you encounter problems with ATM, please report them on the ATM -on Linux mailing list. Subscription information, archives, etc., -can be found on http://icawww1.epfl.ch/linux-atm/ diff -u --recursive --new-file v2.3.42/linux/Documentation/filesystems/bfs.txt linux/Documentation/filesystems/bfs.txt --- v2.3.42/linux/Documentation/filesystems/bfs.txt Sun Nov 7 16:37:33 1999 +++ linux/Documentation/filesystems/bfs.txt Sun Feb 6 18:43:21 2000 @@ -1,13 +1,9 @@ -The BFS filesystem is used on SCO UnixWare machines for /stand slice. -By default, if you attempt to mount it read-write it will be automatically -mounted read-only. If you want to enable (limited) write support, you need -to select "BFS write support" when configuring the kernel. The write support -at this stage is limited to the blocks preallocated for a given inode. -This means that writes beyond the value of inode->iu_eblock will fail with EIO. -In particular, this means you can create empty files but not write data to them -or you can write data to the existing files and increase their size but not the -number of blocks allocated to them. I am currently working on removing this -limitation, i.e. ability to migrate inodes within BFS filesystem. +BFS FILESYSTEM FOR LINUX +======================== + +The BFS filesystem is used by SCO UnixWare OS for the /stand slice, which +usually contains the kernel image and a few other files required for the +boot process. In order to access /stand partition under Linux you obviously need to know the partition number and the kernel must support UnixWare disk slices @@ -29,7 +25,9 @@ # mount -t bfs -o loop stand.img /mnt/stand this will allocate the first available loopback device (and load loop.o -kernel module if necessary) automatically. Beware that umount will not +kernel module if necessary) automatically. If the loopback driver is not +loaded automatically, make sure that your kernel is compiled with kmod +support (CONFIG_KMOD) enabled. Beware that umount will not deallocate /dev/loopN device if /etc/mtab file on your system is a symbolic link to /proc/mounts. You will need to do it manually using "-d" switch of losetup(8). Read losetup(8) manpage for more info. @@ -51,9 +49,9 @@ # od -Ad -tx4 stand.img | more -The first 4 bytes should be 0x1BADFACE. +The first 4 bytes should be 0x1badface. -If you have any questions or suggestions regarding this BFS implementation -please contact me: +If you have any patches, questions or suggestions regarding this BFS +implementation please contact the author: Tigran A. Aivazian . diff -u --recursive --new-file v2.3.42/linux/Documentation/i2c/i2c-protocol linux/Documentation/i2c/i2c-protocol --- v2.3.42/linux/Documentation/i2c/i2c-protocol Mon Dec 20 18:48:21 1999 +++ linux/Documentation/i2c/i2c-protocol Wed Feb 9 18:48:03 2000 @@ -44,3 +44,25 @@ a byte read, followed by a byte write: S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P + + +Modified transactions +===================== + +We have found some I2C devices that needs the following modifications: + + Flag I2C_M_NOSTART: + In a combined transaction, no 'S Addr' is generated at some point. + For example, setting I2C_M_NOSTART on the second partial message + generateds something like: + S Addr Rd [A] [Data] NA Wr [A] Data [A] P + If you set the I2C_M_NOSTART variable for the first partial message, + we do not generate Addr, but we do generate the startbit S. This will + probably confuse all other clients on your bus, so don't try this. + + Flags I2C_M_REV_DIR_ADDR + This toggles the Rd/Wr flag. That is, if you want to do a write, but + need to emit an Rd instead of a Wr, or vice versa, you set this + flag. For example: + S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P + diff -u --recursive --new-file v2.3.42/linux/Documentation/ia64/README linux/Documentation/ia64/README --- v2.3.42/linux/Documentation/ia64/README Wed Dec 31 16:00:00 1969 +++ linux/Documentation/ia64/README Sun Feb 6 18:42:40 2000 @@ -0,0 +1,76 @@ + Linux kernel release 2.3.xx for the IA-64 Platform + + These are the release notes for Linux version 2.3 for IA-64 + platform. This document provides information specific to IA-64 + ONLY, to get additional information about the Linux kernel also + read the original Linux README provided with the kernel. + +INSTALLING the kernel: + + - IA-64 kernel installation is the same as the other platforms, see + original README for details. + + +SOFTWARE REQUIREMENTS + + Compiling and running this kernel requires an IA-64 compliant GCC + compiler. And various software packages also compiled with an + IA-64 compliant GCC compiler. + + +CONFIGURING the kernel: + + Configuration is the same, see original README for details. + + +COMPILING the kernel: + + - Compiling this kernel doesn't differ from other platform so read + the original README for details BUT make sure you have an IA-64 + compliant GCC compiler. + +IA-64 SPECIFICS + + - Security related issues: + + o mmap needs to check whether mapping would overlap with the + address-space hole in a region or whether the mapping would be + across regions. In both cases, mmap should fail. + + o ptrace is a huge security hole right now as it does not reject + writing to security sensitive bits (such as the PSR!). + + - General issues: + + o Kernel modules aren't supported yet. + + o For non-RT signals, siginfo isn't passed through from the kernel + to the point where the signal is actually delivered. Also, we + should make sure the siginfo data is compliant with the UNIX + ABI. + + o Hardly any performance tuning has been done. Obvious targets + include the library routines (memcpy, IP checksum, etc.). Less + obvious targets include making sure we don't flush the TLB + needlessly, etc. Also, the TLB handlers should probably try to + do a speculative load from the virtually mapped linear page + table and only if that fails fall back on walking the page table + tree. + + o Discontigous large memory support; memory above 4GB will be + discontigous since the 4GB-64MB is reserved for firmware and I/O + space. + + o Correct mapping for PAL runtime code; PAL code needs to be + mapped by a TR. + + o Make current IRQ/IOSAPIC handling closer to IA32 such as, + disable/enable interrupts, use of INPROGRESS flag etc. + + o clone system call implementation; needs to setup proper backing + store + + o SMP locks cleanup/optimization + + o IA32 support. Currently experimental. It mostly works but + there are problems with some dynamically loaded programs. diff -u --recursive --new-file v2.3.42/linux/Documentation/networking/atm.txt linux/Documentation/networking/atm.txt --- v2.3.42/linux/Documentation/networking/atm.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/atm.txt Tue Feb 8 18:23:13 2000 @@ -0,0 +1,8 @@ +In order to use anything but the most primitive functions of ATM, +several user-mode programs are required to assist the kernel. These +programs and related material can be found via the ATM on Linux Web +page at http://icawww1.epfl.ch/linux-atm/ + +If you encounter problems with ATM, please report them on the ATM +on Linux mailing list. Subscription information, archives, etc., +can be found on http://icawww1.epfl.ch/linux-atm/ diff -u --recursive --new-file v2.3.42/linux/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt --- v2.3.42/linux/Documentation/networking/decnet.txt Tue Jan 11 22:31:36 2000 +++ linux/Documentation/networking/decnet.txt Tue Feb 8 18:23:13 2000 @@ -27,8 +27,8 @@ CONFIG_PROCFS (to see what's going on) CONFIG_SYSCTL (for easy configuration) -if you want to try out router support (not properly debugged and not -complete yet), you'll need the following options as well... +if you want to try out router support (not properly debugged yet) +you'll need the following options as well... CONFIG_DECNET_RAW (to receive routing packets) CONFIG_DECNET_ROUTER (to be able to add/delete routes) @@ -39,26 +39,26 @@ The kernel command line takes options looking like the following: - decnet=1,2,1 + decnet=1,2 -the first two numbers are the node address 1,2 = 1.2 For 2.2.xx kernels +the two numbers are the node address 1,2 = 1.2 For 2.2.xx kernels and early 2.3.xx kernels, you must use a comma when specifying the DECnet address like this. For more recent 2.3.xx kernels, you may use almost charecter except space, although a `.` would be the most obvious choice :-) -The third number is the level number for routers and is optional. In fact -this option may go away shortly in favour if settings for each interface -seperately. It is probably a good idea to set the DECnet address and type -on boot like this rather than trying to do it later. +There used to be a third number specifying the node type. This option +has gone away in favour of a per interface node type. This is now set +using /proc/sys/net/decnet/conf//forwarding. This file can be +set with a single digit, 0=EndNode, 1=L1 Router and 2=L2 Router. -There are also equivalent options for modules. The node address and type can +There are also equivalent options for modules. The node address can also be set through the /proc/sys/net/decnet/ files, as can other system parameters. -Currently the only supported device is ethernet. You'll have to set the -ethernet address of your ethernet card according to the DECnet address -of the node in order for it to be recognised (and thus appear in +Currently the only supported devices are ethernet and ip_gre. The +ethernet address of your ethernet card has to be set according to the DECnet +address of the node in order for it to be recognised (and thus appear in /proc/net/decnet_dev). There is a utility available at the above FTP sites called dn2ethaddr which can compute the correct ethernet address to use. The address can be set by ifconfig either before at @@ -101,7 +101,8 @@ kernel subsystem is working. - Is the node address set (see /proc/sys/net/decnet/node_address) - - Is the node of the correct type (see /proc/sys/net/decnet/node_type) + - Is the node of the correct type + (see /proc/sys/net/decnet/conf//forwarding) - Is the Ethernet MAC address of each Ethernet card set to match the DECnet address. If in doubt use the dn2ethaddr utility available at the ftp archive. diff -u --recursive --new-file v2.3.42/linux/Documentation/networking/iphase.txt linux/Documentation/networking/iphase.txt --- v2.3.42/linux/Documentation/networking/iphase.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/iphase.txt Tue Feb 8 18:23:13 2000 @@ -0,0 +1,158 @@ + + READ ME FISRT + ATM (i)Chip IA Linux Driver Source +-------------------------------------------------------------------------------- + Read This Before You Begin! +-------------------------------------------------------------------------------- + +Description +----------- + +This is the README file for the Interphase PCI ATM (i)Chip IA Linux driver +source release. + +The features and limitations of this driver are as follows: + - A single VPI (VPI value of 0) is supported. + - Supports 4K VCs for the server board (with 512K control memory) and 1K + VCs for the client board (with 128K control memory). + - UBR, ABR and CBR service categories are supported. + - Only AAL5 is supported. + - Supports setting of PCR on the VCs. + - Multiple adapters in a system are supported. + - All variants of Interphase ATM PCI (i)Chip adapter cards are supported, + including x575 (OC3, control memory 128K , 512K and packet memory 128K, + 512K and 1M), x525 (UTP25) and x531 (DS3 and E3). See + http://www.iphase.com/products/ClassSheet.cfm?ClassID=ATM + for details. + - Only x86 platforms are supported. + - SMP is supported. + + +Before You Start +---------------- + + +Installation +------------ + +1. Installing the adapters in the system + To install the ATM adapters in the system, follow the steps below. + a. Login as root. + b. Shut down the system and power off the system. + c. Install one or more ATM adapters in the system. + d. Connect each adapter to a port on an ATM switch. The green 'Link' + LED on the front panel of the adapter will be on if the adapter is + connected to the switch properly when the system is powered up. + e. Power on and boot the system. + +2. [ Removed ] + +3. Rebuild kernel with ABR support + [ a. and b. removed ] + c. Reconfigure the kernel, choose the Interphase ia driver through "make + menuconfig" or "make xconfig". + d. Rebuild the kernel, loadable modules and the atm tools. + e. Install the new built kernel and modules and reboot. + +4. Load the adapter hardware driver (ia driver) if it is built as a module + a. Login as root. + b. Change directory to /lib/modules//atm. + c. Run "insmod suni.o;insmod iphase.o" + The yellow 'status' LED on the front panel of the adapter will blink + while the driver is loaded in the system. + d. To verify that the 'ia' driver is loaded successfully, run the + following command: + + cat /proc/atm/devices + + If the driver is loaded successfully, the output of the command will + be similar to the following lines: + + Itf Type ESI/"MAC"addr AAL(TX,err,RX,err,drop) ... + 0 ia xxxxxxxxx 0 ( 0 0 0 0 0 ) 5 ( 0 0 0 0 0 ) + + You can also check the system log file /var/log/messages for messages + related to the ATM driver. + +5. Ia Driver Configuration + +5.1 Configuration of adapter buffers + The (i)Chip boards have 3 different packet RAM size variants: 128K, 512K and + 1M. The RAM size decides the number of buffers and buffer size. The default + size and number of buffers are set as following: + + Totol Rx RAM Tx RAM Rx Buf Tx Buf Rx buf Tx buf + RAM size size size size size cnt cnt + -------- ------ ------ ------ ------ ------ ------ + 128K 64K 64K 10K 10K 6 6 + 512K 256K 256K 10K 10K 25 25 + 1M 512K 512K 10K 10K 51 51 + + These setting should work well in most environments, but can be + changed by typing the following command: + + insmod /ia.o IA_RX_BUF= IA_RX_BUF_SZ= \ + IA_TX_BUF= IA_TX_BUF_SZ= + Where: + RX_CNT = number of receive buffers in the range (1-128) + RX_SIZE = size of receive buffers in the range (48-64K) + TX_CNT = number of transmit buffers in the range (1-128) + TX_SIZE = size of transmit buffers in the range (48-64K) + + 1. Transmit and receive buffer size must be a multiple of 4. + 2. Care should be taken so that the memory required for the + transmit and receive buffers is less than or equal to the + total adapter packet memory. + +5.2 Turn on ia debug trace + + When the ia driver is built with the CONFIG_ATM_IA_DEBUG flag, the driver + can provide more debug trace if needed. There is a bit mask variable, + IADebugFlag, which controls the output of the traces. You can find the bit + map of the IADebugFlag in iphase.h. + The debug trace can be turn on through the insmod command line option, for + example, "insmod iphase.o IADebugFlag=0xffffffff" can turn on all the debug + traces together with loading the driver. + +6. Ia Driver Test Using ttcp_atm and PVC + + For the PVC setup, the test machines can either be connected back-to-back or + through a switch. If connected through the switch, the switch must be + configured for the PVC(s). + + a. For UBR test: + At the test machine intended to receive data, type: + ttcp_atm -r -a -s 0.100 + At the other test machine, type: + ttcp_atm -t -a -s 0.100 -n 10000 + Run "ttcp_atm -h" to display more options of the ttcp_atm tool. + b. For ABR test: + It is the same as the UBR testing, but with an extra command option: + -Pabr:max_pcr= + where: + xxx = the maximum peak cell rate, from 170 - 353207. + This option must be set on both the machines. + c. For CBR test: + It is the same as the UBR testing, but with an extra command option: + -Pcbr:max_pcr= + where: + xxx = the maximum peak cell rate, from 170 - 353207. + This option may only be set on the trasmit machine. + + +OUTSTANDING ISSUES +------------------ + + + +Contact Information +------------------- + + Customer Support: + United States: Telephone: (214) 654-5555 + Fax: (214) 654-5500 + E-Mail: intouch@iphase.com + Europe: Telephone: 33 (0)1 41 15 44 00 + Fax: 33 (0)1 41 15 12 13 + World Wide Web: http://www.iphase.com + Anonymous FTP: ftp.iphase.com diff -u --recursive --new-file v2.3.42/linux/Documentation/networking/tlan.txt linux/Documentation/networking/tlan.txt --- v2.3.42/linux/Documentation/networking/tlan.txt Tue Dec 7 09:32:38 1999 +++ linux/Documentation/networking/tlan.txt Mon Feb 7 09:53:20 2000 @@ -1,25 +1,8 @@ +(C) 1997-1998 Caldera, Inc. +(C) 1998 James Banks +(C) 1999-2000 Torben Mathiasen - -I haven't had any time to do anything for a long time, and this isn't -likely to change. So there's a driver here for anyone looking to -carry forward a project :) - -For those who are looking for help, I can't. I haven't looked at -a kernel since the early 2.0 series, so I won't know what's going on. -Your best chance at help would be joining the TLAN mailing list and -posting your question there. - -You can join by sending "subscribe tlan" in the body of an email to -majordomo@vuser.vu.union.edu. - -Thanks to those who have (and who will ;) put work in to keep the TLAN -driver working as the kernel moves on. - -James -james@sovereign.org - - -TLAN driver for Linux, version 1.0 +TLAN driver for Linux, version 1.3 README @@ -57,43 +40,7 @@ but I do not expect any problems. -II. Building the Driver. - - The TLAN driver may be compiled into the kernel, or it may be compiled - as a module separately, or in the kernel. A patch is included for - 2.0.29 (which also works for 2.0.30, 2.0.31, and 2.0.32). - - To compile it as part of the kernel: - 1. Download and untar the TLAN driver package. - 2. If your kernel is 2.1.45 or later, you do not need to patch the - kernel sources. Copy the tlan.c and tlan.h to drivers/net in - the kernel source tree. - 3. Otherwise, apply the appropriate patch for your kernel. For - example: - - cd /usr/src/linux - patch -p1 < kernel.2.0.29 - - 4. Copy the files tlan.c and tlan.h from the TLAN package to the - directory drivers/net in the Linux kernel source tree. - 5. Configure your kernel for the TLAN driver. Answer 'Y' when - prompted to ask about experimental code (the first question). - Then answer 'Y' when prompted if to include TI ThunderLAN - support. If you want the driver compiled as a module, answer 'M' - instead of 'Y'. - 6. Make the kernel and, if necessary, the modules. - - To compile the TLAN driver independently: - 1. Download and untar the TLAN driver package. - 2. Change to the tlan directory. - 3. If you are NOT using a versioned kernel (ie, want an non- - versioned module), edit the Makefile, and comment out the - line: - MODVERSIONS = -DMODVERSIONS - 4. Run 'make'. - - -III. Driver Options +II. Driver Options 1. You can append debug=x to the end of the insmod line to get debug messages, where x is a bit field where the bits mean the following: @@ -110,18 +57,20 @@ device that does not have an AUI/BNC connector will probably cause it to not function correctly.) - 4. You can set duplex=1 to force half duplex, and duplex=2 to + 3. You can set duplex=1 to force half duplex, and duplex=2 to force full duplex. - 5. You can set speed=10 to force 10Mbs operation, and speed=100Mbs + 4. You can set speed=10 to force 10Mbs operation, and speed=100 to force 100Mbs operation. (I'm not sure what will happen if a card which only supports 10Mbs is forced into 100Mbs mode.) - 3. If the driver is built into the kernel, you can use the 3rd + 5. If the driver is built into the kernel, you can use the 3rd and 4th parameters to set aui and debug respectively. For example: +/* kernel-parameters are currently not supported. I will fix this asap. */ + ether=0,0,0x1,0x7,eth0 This sets aui to 0x1 and debug to 0x7, assuming eth0 is a @@ -130,19 +79,17 @@ The bits in the third byte are assigned as follows: 0x01 = aui - 0x02 = use SA_INTERRUPT flag when reserving the irq. 0x04 = use half duplex 0x08 = use full duplex 0x10 = use 10BaseT 0x20 = use 100BaseTx -IV. Things to try if you have problems. +III. Things to try if you have problems. 1. Make sure your card's PCI id is among those listed in section I, above. - 1. Make sure routing is correct. - 2. If you are using a 2.1.x kernel, try to duplicate the - problem on a 2.0.x (preferably 2.0.29 or 2.0.30) kernel. + 2. Make sure routing is correct. + 3. Try forcing different speed/duplex settings There is also a tlan mailing list which you can join by sending "subscribe tlan" diff -u --recursive --new-file v2.3.42/linux/Documentation/pci.txt linux/Documentation/pci.txt --- v2.3.42/linux/Documentation/pci.txt Thu Jan 6 12:57:47 2000 +++ linux/Documentation/pci.txt Mon Feb 7 12:13:07 2000 @@ -1,52 +1,130 @@ - Few Notes About The PCI Subsystem + How To Write Linux PCI Drivers - or - - "What should you avoid when writing PCI drivers" - - by Martin Mares on 21-Nov-1999 + by Martin Mares on 07-Feb-2000 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The world of PCI is vast and it's full of (mostly unpleasant) surprises. +Different PCI devices have different requirements and different bugs -- +because of this, the PCI support layer in Linux kernel is not as trivial +as one would wish. This short pamphlet tries to help all potential driver +authors to find their way through the deep forests of PCI handling. + 0. Structure of PCI drivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Aa typical PCI device driver needs to perform the following actions: +There exist two kinds of PCI drivers: new-style ones (which leave most of +probing for devices to the PCI layer and support online insertion and removal +of devices [thus supporting PCI, hot-pluggable PCI and CardBus in single +driver]) and old-style ones which just do all the probing themselves. Unless +you have a very good reason to do so, please don't use the old way of probing +in any new code. After the driver finds the devices it wishes to operate +on (either the old or the new way), it needs to perform the following steps: + + Enable the device + Access device configuration space + Discover resources (addresses and IRQ numbers) provided by the device + Allocate these resources + Communicate with the device + +Most of these topics are covered by the following sections, for the rest +look at , it's hopefully well commented. + +If the PCI subsystem is not configured (CONFIG_PCI is not set), most of +the functions described below are defined as inline functions either completely +empty or just returning an appropriate error codes to avoid lots of ifdefs +in the drivers. + + +1. New-style drivers +~~~~~~~~~~~~~~~~~~~~ +The new-style drivers just call pci_register_driver during their initialization +with a pointer to a structure describing the driver (struct pci_driver) which +contains: + + name Name of the driver + id_table Pointer to table of device ID's the driver is + interested in + probe Pointer to a probing function which gets called (during + execution of pci_register_driver for already existing + devices or later if a new device gets inserted) for all + PCI devices which match the ID table and are not handled + by the other drivers yet. This function gets passed a pointer + to the pci_dev structure representing the device and also + which entry in the ID table did the device match. It returns + zero when the driver has accepted the device or an error + code (negative number) otherwise. This function always gets + called from process context, so it can sleep. + remove Pointer to a function which gets called whenever a device + being handled by this driver is removed (either during + deregistration of the driver or when it's manually pulled + out of a hot-pluggable slot). This function can be called + from interrupt context. + suspend, Power management hooks (currently used only for CardBus + resume cards) -- called when the device goes to sleep or is + resumed. + +The ID table is an array of struct pci_device_id ending with a all-zero entry. +Each entry consists of: + + vendor, device Vendor and device ID to match (or PCI_ANY_ID) + subvendor, Subsystem vendor and device ID to match (or PCI_ANY_ID) + subdevice + 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. + +When the driver exits, it just calls pci_deregister_driver() and the PCI layer +automatically calls the remove hook for all devices handled by the driver. + +Please mark the initialization and cleanup functions where appropriate +(the corresponding macros are defined in ): + + __init Initialization code. Thrown away after the driver + initializes. + __exit Exit code. Ignored for non-modular drivers. + __devinit Device initialization code. Identical to __init if + the kernel is not compiled with CONFIG_HOTPLUG, normal + function otherwise. + __devexit The same for __exit. + + +2. How to find PCI devices manually (the old style) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +PCI drivers not using the pci_register_driver() interface search +for PCI devices manually using the following constructs: + +Searching by vendor and device ID: + + struct pci_dev *dev = NULL; + while (dev = pci_find_device(VENDOR_ID, DEVICE_ID, dev)) + configure_device(dev); + +Searching by class ID (iterate in a similar way): - 1. Find PCI devices it's able to handle - 2. Enable them - 3. Access their configuration space - 4. Discover addresses and IRQ numbers - -1. How to find PCI devices -~~~~~~~~~~~~~~~~~~~~~~~~~~ - In case your driver wants to search for all devices with given vendor/device -ID, it should use: - - struct pci_dev *dev = NULL; - while (dev = pci_find_device(VENDOR_ID, DEVICE_ID, dev)) - configure_device(dev); + pci_find_class(CLASS_ID, dev) - For class-based search, use pci_find_class(CLASS_ID, dev). +Searching by both vendor/device and subsystem vendor/device ID: - If you need to match by subsystem vendor/device ID, use -pci_find_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev). + pci_find_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev). You can use the constant PCI_ANY_ID as a wildcard replacement for VENDOR_ID or DEVICE_ID. This allows searching for any device from a specific vendor, for example. - In case you want to do some complex matching, you can walk the list of all -known PCI devices: + In case you need to decide according to some more complex criteria, +you can walk the list of all known PCI devices yourself: - struct pci_dev *dev; - pci_for_each_dev(dev) { - ... do anything you want with dev ... - } + struct pci_dev *dev; + pci_for_each_dev(dev) { + ... do anything you want with dev ... + } - The `struct pci_dev *' pointer serves as an identification of a PCI device -and is passed to all other functions operating on PCI devices. +For compatibility with device ordering in older kernels, you can also +use pci_for_each_dev_reverse(dev) for walking the list in the opposite +direction. -2. Enabling devices + +3. Enabling devices ~~~~~~~~~~~~~~~~~~~ Before you do anything with the device you've found, you need to enable it by calling pci_enable_device() which enables I/O and memory regions of @@ -57,7 +135,8 @@ which enables the bus master bit in PCI_COMMAND register and also fixes the latency timer value if it's set to something bogus by the BIOS. -3. How to access PCI config space + +4. How to access PCI config space ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can use pci_(read|write)_config_(byte|word|dword) to access the config space of a device represented by struct pci_dev *. All these functions return 0 @@ -72,7 +151,8 @@ pci_find_capability() for the particular capability and it will find the corresponding register block for you. -4. Addresses and interrupts + +5. Addresses and interrupts ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Memory and port addresses and interrupt numbers should NOT be read from the config space. You should use the values in the pci_dev structure as they might @@ -86,13 +166,33 @@ All interrupt handlers should be registered with SA_SHIRQ and use the devid to map IRQs to devices (remember that all PCI interrupts are shared). -5. Other interesting functions + +6. Other interesting functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pci_find_slot() Find pci_dev corresponding to given bus and slot numbers. pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3) +pci_find_capability() Find specified capability in device's capability + list. + + +7. Miscellaneous hints +~~~~~~~~~~~~~~~~~~~~~~ +When displaying PCI slot names to the user (for example when a driver wants +to tell the user what card has it found), please use pci_dev->slot_name +for this purpose. + +Always refer to the PCI devices by a pointer to the pci_dev structure. +All PCI layer functions use this identification and it's the only +reasonable one. Don't use bus/slot/function numbers except for very +special purposes -- on systems with multiple primary buses their semantics +can be pretty complex. + +If you're going to use PCI bus mastering DMA, take a look at +Documentation/DMA-mapping.txt. + -6. Obsolete functions +8. Obsolete functions ~~~~~~~~~~~~~~~~~~~~~ There are several functions kept only for compatibility with old drivers not updated to the new PCI interface. Please don't use them in new code. diff -u --recursive --new-file v2.3.42/linux/Documentation/pm.txt linux/Documentation/pm.txt --- v2.3.42/linux/Documentation/pm.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/pm.txt Tue Feb 8 11:28:31 2000 @@ -0,0 +1,166 @@ + Linux Power Management Support + +This document briefly describes how to use power management with your +Linux system and how to add power management support to Linux drivers. + +APM or ACPI? +------------ +If you have a relatively recent x86 mobile, desktop, or server system, +odds are it supports either Advanced Power Management (APM) or +Advanced Configuration and Power Interface (ACPI). ACPI is the newer +of the two technologies and puts power management in the hands of the +operating system, allowing for more intelligent power management than +is possible with BIOS controlled APM. + +The best way to determine which, if either, your system supports is to +build a kernel with both ACPI and APM enabled (as of 2.3.x ACPI is +enabled by default). If a working ACPI implementation is found, the +ACPI driver will override and disable APM, otherwise the APM driver +will be used. + +No sorry, you can not have both ACPI and APM enabled and running at +once. Some people with broken ACPI or broken APM implementations +would like to use both to get a full set of working features, but you +simply can not mix and match the two. Only one power management +interface can be in control of the machine at once. Think about it.. + +User-space Daemons +------------------ +Both APM and ACPI rely on user-space daemons, apmd and acpid +respectively, to be completely functional. Obtain both of these +daemons from your Linux distribution or from the Internet (see below) +and be sure that they are started sometime in the system boot process. +Go ahead and start both. If ACPI or APM is not available on your +system the associated daemon will exit gracefully. + + apmd: http://linuxcare.com.au/apm/ + acpid: http://phobos.fs.tum.de/acpi/ + +Driver Interface +---------------- +If you are writing a new driver or maintaining an old driver, it +should include power management support. Without power management +support, a single driver may prevent a system with power management +capabilities from ever being able to suspend (safely). + +Overview: +1) Register each instance of a device with "pm_register" +2) Call "pm_access" before accessing the hardware. + (this will ensure that the hardware is awake and ready) +3) Your "pm_callback" is called before going into a + suspend state (ACPI D1-D3) or after resuming (ACPI D0) + from a suspend. +4) Call "pm_dev_idle" when the device is not being used + (optional but will improve device idle detection) +5) When unloaded, unregister the device with "pm_unregister" + +/* + * Description: Register a device with the power-management subsystem + * + * Parameters: + * type - device type (PCI device, system device, ...) + * id - instance number or unique identifier + * cback - request handler callback (suspend, resume, ...) + * + * Returns: Registered PM device or NULL on error + * + * Examples: + * dev = pm_register(PM_SYS_DEV, PM_SYS_VGA, vga_callback); + * + * struct pci_dev *pci_dev = pci_find_dev(...); + * dev = pm_register(PM_PCI_DEV, PM_PCI_ID(pci_dev), callback); + */ +struct pm_dev *pm_register(pm_dev_t type, unsigned long id, pm_callback cback); + +/* + * Description: Unregister a device with the power management subsystem + * + * Parameters: + * dev - PM device previously returned from pm_register + */ +void pm_unregister(struct pm_dev *dev); + +/* + * Description: Unregister all devices with a matching callback function + * + * Parameters: + * cback - previously registered request callback + * + * Notes: Provided for easier porting from old APM interface + */ +void pm_unregister_all(pm_callback cback); + +/* + * Device idle/use detection + * + * In general, drivers for all devices should call "pm_access" + * before accessing the hardware (ie. before reading or modifying + * a hardware register). Request or packet-driven drivers should + * additionally call "pm_dev_idle" when a device is not being used. + * + * Examples: + * 1) A keyboard driver would call pm_access whenever a key is pressed + * 2) A network driver would call pm_access before submitting + * a packet for transmit or receive and pm_dev_idle when its + * transfer and receive queues are empty. + * 3) A VGA driver would call pm_access before it accesses any + * of the video controller registers + * + * Ultimately, the PM policy manager uses the access and idle + * information to decide when to suspend individual devices + * or when to suspend the entire system + */ + +/* + * Description: Update device access time and wake up device, if necessary + * + * Parameters: + * dev - PM device previously returned from pm_register + * + * Details: If called from an interrupt handler pm_access updates + * access time but should never need to wake up the device + * (if device is generating interrupts, it should be awake + * already) This is important as we can not wake up + * devices from an interrupt handler. + */ +void pm_access(struct pm_dev *dev); + +/* + * Description: Identify device as currently being idle + * + * Parameters: + * dev - PM device previously returned from pm_register + * + * Details: A call to pm_dev_idle might signal to the policy manager + * to put a device to sleep. If a new device request arrives + * between the call to pm_dev_idle and the pm_callback + * callback, the driver should fail the pm_callback request. + */ +void pm_dev_idle(struct pm_dev *dev); + +/* + * Power management request callback + * + * Parameters: + * dev - PM device previously returned from pm_register + * rqst - request type + * data - data, if any, associated with the request + * + * Returns: 0 if the request is successful + * EINVAL if the request is not supported + * EBUSY if the device is now busy and can not handle the request + * ENOMEM if the device was unable to handle the request due to memory + * + * Details: The device request callback will be called before the + * device/system enters a suspend state (ACPI D1-D3) or + * or after the device/system resumes from suspend (ACPI D0). + * For PM_SUSPEND, the ACPI D-state being entered is passed + * as the "data" argument to the callback. The device + * driver should save (PM_SUSPEND) or restore (PM_RESUME) + * device context when the request callback is called. + * + * Once a driver returns 0 (success) from a suspend + * request, it should not process any further requests or + * access the device hardware until a call to "pm_access" is made. + */ +typedef int (*pm_callback)(struct pm_dev *dev, pm_request_t rqst, void *data); diff -u --recursive --new-file v2.3.42/linux/Documentation/sound/CMI8330 linux/Documentation/sound/CMI8330 --- v2.3.42/linux/Documentation/sound/CMI8330 Sun Nov 7 16:37:33 1999 +++ linux/Documentation/sound/CMI8330 Wed Feb 9 18:48:03 2000 @@ -1,3 +1,83 @@ +Documentation for CMI 8330 (SoundPRO) +------------------------------------- +Alessandro Zummo + +This adapter is now directly supported by the sb driver. + + The only thing you have to do is to compile the kernel sound +support as a module and to enable kernel ISAPnP support, +as shown below. + + +CONFIG_SOUND=m +CONFIG_SOUND_SB=m + +CONFIG_PNP=y +CONFIG_ISAPNP=y + + +and optionally: + + +CONFIG_SOUND_MPU401=m + + for MPU401 support. + + +CONFIG_SOUND_YM3812=m + + for OPL3 support. Please note that there are better ways to play midi files, like + timidity or the softoss2 module. + + +CONFIG_JOYSTICK=y + + to activate the joystick port. + + +(I suggest you to use "make menuconfig" or "make xconfig" + for a more comfortable configuration editing) + + + +Then you can do + + modprobe sb + +and everything will be (hopefully) configured. + +You should get something similar in syslog: + +sb: CMI8330 detected. +sb: CMI8330 sb base located at 0x220 +sb: CMI8330 mpu base located at 0x330 +sb: CMI8330 gameport base located at 0x200 +sb: CMI8330 opl3 base located at 0x388 +sb: CMI8330 mail reports to Alessandro Zummo +sb: ISAPnP reports CMI 8330 SoundPRO at i/o 0x220, irq 7, dma 1,5 + + + + +To activate the OPL3 support, you need these lines in /etc/modules.conf +or in a file in /etc/modutils + +alias synth0 opl3 +options opl3 io=0x388 + +and then you can do: + + modprobe opl3 + + + + + + +The old documentation file follows for reference +purposes. + + How to enable CMI 8330 (SOUNDPRO) soundchip on Linux ------------------------------------------ Stefan Laudat diff -u --recursive --new-file v2.3.42/linux/Documentation/usb/ibmcam.txt linux/Documentation/usb/ibmcam.txt --- v2.3.42/linux/Documentation/usb/ibmcam.txt Fri Jan 28 15:09:06 2000 +++ linux/Documentation/usb/ibmcam.txt Mon Feb 7 19:15:56 2000 @@ -23,11 +23,30 @@ IBM "C-It" camera, also known as "Xirlink PC Camera" The device uses proprietary ASIC (and compression method); -it is manufactured by Xirlink. See http://www.xirlink.com +it is manufactured by Xirlink. See http://www.xirlink.com/ +or http://www.c-itnow.com/ for details and pictures. + +The Linux driver was developed with camera with following +model number (or FCC ID): KSX-XVP510. This camera has three +interfaces, each with one endpoint (control, iso, iso). + +It appears that Xirlink made some changes in their cameras recently. +In particular, following models [FCC ID] are suspect; one with +with FCC ID KSX-X9903 is known to be one of them: + +XVP300 [KSX-X9903] +XVP600 [KSX-X9902] +XVP610 [KSX-X9902] + +(see http://www.xirlink.com/ibmpccamera/ for updates, they refer +to these new cameras by Windows driver dated 12-27-99, v3005 BETA) +These cameras have two interfaces, one endpoint in each (iso, bulk). +Attempts to remotely debug one of these cameras weren't successful. +I'd need to have a camera to figure out how to use it. WHAT YOU NEED: -- An IBM C-it camera +- A supported IBM PC (C-it) camera (see above) - A Linux box with USB support (2.3/2.4 or 2.2 w/backport) @@ -73,6 +92,7 @@ debug Integer 0-9 [0] debug=1 flags Integer 0-0xFF [0] flags=0x0d framerate Integer 0-6 [2] framerate=1 +hue_correction Integer 0-255 [128] hue_correction=115 init_brightness Integer 0-255 [128] init_brightness=100 init_contrast Integer 0-255 [192] init_contrast=200 init_color Integer 0-255 [128] init_color=130 @@ -108,6 +128,16 @@ Beware - fast settings are very demanding and may not work well with all video sizes. Be conservative. +hue_correction This highly optional setting allows to adjust the + hue of the image in a way slightly different from + what usual "hue" control does. Both controls affect + YUV colorspace: regular "hue" control adjusts only + U component, and this "hue_correction" option similarly + adjusts only V component. However usually it is enough + to tweak only U or V to compensate for colored light or + color temperature; this option simply allows more + complicated correction when and if it is necessary. + init_brightness These settings specify _initial_ values which will be init_contrast used to set up the camera. If your V4L application has init_color its own controls to adjust the picture then these @@ -143,8 +173,8 @@ WHAT NEEDS TO BE DONE: -- The box freezes if working camera (with xawtv) is unplugged (OHCI). - Workaround: don't do that :) End the V4L application first. +- The box freezes if camera is unplugged after being used (OHCI). + Workaround: don't do that :) - Some USB frames are lost on high frame rates, though they shouldn't - ViCE compression (Xirlink proprietary) may improve frame rate - On occasion camera does not start properly; xawtv reports errors. diff -u --recursive --new-file v2.3.42/linux/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt --- v2.3.42/linux/Documentation/usb/ov511.txt Fri Jan 28 15:09:06 2000 +++ linux/Documentation/usb/ov511.txt Wed Feb 9 11:51:13 2000 @@ -15,12 +15,13 @@ ________________________________________________________ Manufacturer | Model | Custom ID | Status -----------------+----------------+-----------+--------- -MediaForte | MV300 | 0 | Untested +MediaForte | MV300 | 0 | Working D-Link | DSB-C300 | 3 | Working +Puretek | PT-6007 | 5 | Untested Creative Labs | WebCam 3 | 21 | Working Lifeview | RoboCam | 100 | Untested AverMedia | InterCam Elite | 102 | Working -MediaForte | MV300 | 112 | Untested +MediaForte | MV300 | 112 | Working -------------------------------------------------------- Any camera using the OV511 and the OV7610 CCD should work with this driver. The @@ -78,7 +79,9 @@ make make install -Now you should be able to run xawtv. Right click for the options dialog. +Now you should be able to run xawtv. Right click for the options dialog. If +you get a scrambled image it is likely that you made a mistake in Xawtv.ad. +Try setting the size to 320x240 if all else fails. WORKING FEATURES: o Color streaming/capture at 640x480 and 320x240 diff -u --recursive --new-file v2.3.42/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.42/linux/MAINTAINERS Tue Feb 1 01:35:43 2000 +++ linux/MAINTAINERS Wed Feb 9 19:43:47 2000 @@ -561,7 +561,7 @@ LINUX FOR POWERPC P: Cort Dougan -M: cort@ppc.kernel.org +M: cort@fsmlabs.com W: http://www.ppc.kernel.org/ S: Maintained @@ -826,6 +826,12 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +SA1100 SUPPORT +P: Nicolas Pitre +M: nico@cam.org +L: sa1100-linux@pa.dec.com +S: Maintained + SBPCD CDROM DRIVER P: Eberhard Moenkeberg M: emoenke@gwdg.de @@ -880,6 +886,11 @@ P: Linus Torvalds M: torvalds@transmeta.com L: linux-smp@vger.rutgers.edu +S: Maintained + +SOFTWARE RAID (Multiple Disks) SUPPORT +P: Ingo Molnar +M: mingo@redhat.com S: Maintained SONIC NETWORK DRIVER diff -u --recursive --new-file v2.3.42/linux/Makefile linux/Makefile --- v2.3.42/linux/Makefile Tue Feb 1 01:35:43 2000 +++ linux/Makefile Tue Feb 8 22:26:49 2000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 42 +SUBLEVEL = 43 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.3.42/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.3.42/linux/arch/alpha/config.in Fri Jan 21 18:19:15 2000 +++ linux/arch/alpha/config.in Tue Feb 8 18:37:43 2000 @@ -55,11 +55,15 @@ # clear all implied options (don't want default values for those): unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 -unset CONFIG_PCI CONFIG_ALPHA_EISA +unset CONFIG_PCI CONFIG_ISA CONFIG_ALPHA_EISA unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA unset CONFIG_ALPHA_IRONGATE + +# Most of these machines have ISA slots; not exactly sure which don't, +# and this doesn't activate hordes of code, so do it always. +define_bool CONFIG_ISA y if [ "$CONFIG_ALPHA_GENERIC" = "y" ] then diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.3.42/linux/arch/alpha/kernel/Makefile Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/Makefile Mon Feb 7 20:09:05 2000 @@ -26,11 +26,11 @@ sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o \ sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \ sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \ - es1888.o smc37c669.o smc37c93x.o ns87312.o pci.o + es1888.o smc37c669.o smc37c93x.o ns87312.o pci.o pci_iommu.o else ifdef CONFIG_PCI -O_OBJS += pci.o +O_OBJS += pci.o pci_iommu.o endif # Core logic support diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.3.42/linux/arch/alpha/kernel/alpha_ksyms.c Wed Dec 15 10:43:16 1999 +++ linux/arch/alpha/kernel/alpha_ksyms.c Wed Feb 9 20:08:09 2000 @@ -149,6 +149,9 @@ EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__up_wakeup); +EXPORT_SYMBOL_NOVERS(__down_read_failed); +EXPORT_SYMBOL_NOVERS(__down_write_failed); +EXPORT_SYMBOL_NOVERS(__rwsem_wake); /* * SMP-specific symbols. @@ -161,10 +164,7 @@ EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(cpu_number_map); -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(global_bh_count); -EXPORT_SYMBOL(synchronize_bh); +EXPORT_SYMBOL(__cpu_number_map); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c --- v2.3.42/linux/arch/alpha/kernel/core_apecs.c Tue Nov 23 22:42:20 1999 +++ linux/arch/alpha/kernel/core_apecs.c Mon Feb 7 20:09:05 2000 @@ -356,22 +356,49 @@ write_dword: apecs_write_config_dword }; +void +apecs_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + wmb(); + *(vip)APECS_IOC_TBIA = 0; + mb(); +} + void __init apecs_init_arch(void) { struct pci_controler *hose; /* - * Set up the PCI->physical memory translation windows. - * For now, window 2 is disabled. In the future, we may - * want to use it to do scatter/gather DMA. Window 1 - * goes at 1 GB and is 1 GB large. + * Create our single hose. + */ + + pci_isa_hose = hose = alloc_pci_controler(); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = APECS_CONF; + hose->index = 0; + + /* + * Set up the PCI to main memory translation windows. + * + * Window 1 is direct access 1GB at 1GB + * Window 2 is scatter-gather 8MB at 8MB (for isa) */ - *(vuip)APECS_IOC_PB1R = 1UL << 19 | (APECS_DMA_WIN_BASE & 0xfff00000U); - *(vuip)APECS_IOC_PM1R = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U; + hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); + hose->sg_pci = NULL; + __direct_map_base = 0x40000000; + __direct_map_size = 0x40000000; + + *(vuip)APECS_IOC_PB1R = __direct_map_base | 0x00080000; + *(vuip)APECS_IOC_PM1R = (__direct_map_size - 1) & 0xfff00000U; *(vuip)APECS_IOC_TB1R = 0; - *(vuip)APECS_IOC_PB2R = 0U; /* disable window 2 */ + *(vuip)APECS_IOC_PB2R = hose->sg_isa->dma_base | 0x000c0000; + *(vuip)APECS_IOC_PM2R = (hose->sg_isa->size - 1) & 0xfff00000; + *(vuip)APECS_IOC_TB2R = virt_to_phys(hose->sg_isa->ptes) >> 1; + + apecs_pci_tbi(hose, 0, -1); /* * Finally, clear the HAXR2 register, which gets used @@ -381,16 +408,6 @@ */ *(vuip)APECS_IOC_HAXR2 = 0; mb(); - - /* - * Create our single hose. - */ - - hose = alloc_pci_controler(); - hose->io_space = &ioport_resource; - hose->mem_space = &iomem_resource; - hose->config_space = APECS_CONF; - hose->index = 0; } void diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- v2.3.42/linux/arch/alpha/kernel/core_cia.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/core_cia.c Mon Feb 7 20:09:33 2000 @@ -314,12 +314,20 @@ write_dword: cia_write_config_dword }; +void +cia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + wmb(); + *(vip)CIA_IOC_PCI_TBIA = 3; /* Flush all locked and unlocked. */ + mb(); +} + void __init cia_init_arch(void) { struct pci_controler *hose; struct resource *hae_mem; - unsigned int temp; + unsigned int temp; #if DEBUG_DUMP_REGS temp = *(vuip)CIA_IOC_CIA_REV; mb(); @@ -368,63 +376,11 @@ printk("cia_init: W3_BASE was 0x%x\n", temp); #endif /* DEBUG_DUMP_REGS */ - /* - * Set up error reporting. - */ - temp = *(vuip)CIA_IOC_CIA_ERR; - temp |= 0x180; /* master, target abort */ - *(vuip)CIA_IOC_CIA_ERR = temp; - mb(); - - temp = *(vuip)CIA_IOC_CIA_CTRL; - temp |= 0x400; /* turn on FILL_ERR to get mchecks */ - *(vuip)CIA_IOC_CIA_CTRL = temp; - mb(); - - /* - * Set up the PCI->physical memory translation windows. - * For now, windows 2 and 3 are disabled. In the future, - * we may want to use them to do scatter/gather DMA. - * - * Window 0 goes at 1 GB and is 1 GB large. - * Window 1 goes at 2 GB and is 1 GB large. - */ - - *(vuip)CIA_IOC_PCI_W0_BASE = CIA_DMA_WIN0_BASE_DEFAULT | 1U; - *(vuip)CIA_IOC_PCI_W0_MASK = (CIA_DMA_WIN0_SIZE_DEFAULT - 1) & - 0xfff00000U; - *(vuip)CIA_IOC_PCI_T0_BASE = CIA_DMA_WIN0_TRAN_DEFAULT >> 2; - - *(vuip)CIA_IOC_PCI_W1_BASE = CIA_DMA_WIN1_BASE_DEFAULT | 1U; - *(vuip)CIA_IOC_PCI_W1_MASK = (CIA_DMA_WIN1_SIZE_DEFAULT - 1) & - 0xfff00000U; - *(vuip)CIA_IOC_PCI_T1_BASE = CIA_DMA_WIN1_TRAN_DEFAULT >> 2; - - *(vuip)CIA_IOC_PCI_W2_BASE = 0x0; - *(vuip)CIA_IOC_PCI_W3_BASE = 0x0; - mb(); - - /* - * Next, clear the CIA_CFG register, which gets used - * for PCI Config Space accesses. That is the way - * we want to use it, and we do not want to depend on - * what ARC or SRM might have left behind... - */ - *((vuip)CIA_IOC_CFG) = 0; mb(); - - /* - * Zero the HAEs. - */ - *((vuip)CIA_IOC_HAE_MEM) = 0; mb(); - *((vuip)CIA_IOC_HAE_MEM); /* read it back. */ - *((vuip)CIA_IOC_HAE_IO) = 0; mb(); - *((vuip)CIA_IOC_HAE_IO); /* read it back. */ - /* * Create our single hose. */ - hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controler(); hae_mem = alloc_resource(); hose->io_space = &ioport_resource; @@ -439,6 +395,64 @@ if (request_resource(&iomem_resource, hae_mem) < 0) printk(KERN_ERR "Failed to request HAE_MEM\n"); + + /* + * Set up the PCI to main memory translation windows. + * + * Window 0 is scatter-gather 8MB at 8MB (for isa) + * Window 1 is scatter-gather 128MB at 1GB + * Window 2 is direct access 2GB at 2GB + * ??? We ought to scale window 1 with memory. + */ + + /* NetBSD hints that page tables must be aligned to 32K due + to a hardware bug. No description of what models affected. */ + hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 32768); + hose->sg_pci = iommu_arena_new(0x40000000, 0x08000000, 32768); + __direct_map_base = 0x80000000; + __direct_map_size = 0x80000000; + + *(vuip)CIA_IOC_PCI_W0_BASE = hose->sg_isa->dma_base | 3; + *(vuip)CIA_IOC_PCI_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000; + *(vuip)CIA_IOC_PCI_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2; + + *(vuip)CIA_IOC_PCI_W1_BASE = hose->sg_pci->dma_base | 3; + *(vuip)CIA_IOC_PCI_W1_MASK = (hose->sg_pci->size - 1) & 0xfff00000; + *(vuip)CIA_IOC_PCI_T1_BASE = virt_to_phys(hose->sg_pci->ptes) >> 2; + + *(vuip)CIA_IOC_PCI_W2_BASE = __direct_map_base | 1; + *(vuip)CIA_IOC_PCI_W2_MASK = (__direct_map_size - 1) & 0xfff00000; + *(vuip)CIA_IOC_PCI_T2_BASE = 0; + + *(vuip)CIA_IOC_PCI_W3_BASE = 0; + + cia_pci_tbi(hose, 0, -1); + + /* + * Set up error reporting. + */ + temp = *(vuip)CIA_IOC_CIA_ERR; + temp |= 0x180; /* master, target abort */ + *(vuip)CIA_IOC_CIA_ERR = temp; + + temp = *(vuip)CIA_IOC_CIA_CTRL; + temp |= 0x400; /* turn on FILL_ERR to get mchecks */ + *(vuip)CIA_IOC_CIA_CTRL = temp; + + /* + * Next, clear the CIA_CFG register, which gets used + * for PCI Config Space accesses. That is the way + * we want to use it, and we do not want to depend on + * what ARC or SRM might have left behind... + */ + *(vuip)CIA_IOC_CFG = 0; + + /* + * Zero the HAEs. + */ + *(vuip)CIA_IOC_HAE_MEM = 0; + *(vuip)CIA_IOC_HAE_IO = 0; + mb(); } static inline void @@ -456,6 +470,8 @@ cia_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { + int expected; + /* Clear the error before any reporting. */ mb(); mb(); /* magic */ @@ -464,5 +480,23 @@ wrmces(rdmces()); /* reset machine check pending flag. */ mb(); - process_mcheck_info(vector, la_ptr, regs, "CIA", mcheck_expected(0)); + expected = mcheck_expected(0); + if (!expected && vector == 0x660) { + struct el_common *com; + struct el_common_EV5_uncorrectable_mcheck *ev5; + struct el_CIA_sysdata_mcheck *cia; + + com = (void *)la_ptr; + ev5 = (void *)(la_ptr + com->proc_offset); + cia = (void *)(la_ptr + com->sys_offset); + + if (com->code == 0x202) { + printk(KERN_CRIT "CIA PCI machine check: err0=%08x " + "err1=%08x err2=%08x\n", + (int) cia->pci_err0, (int) cia->pci_err1, + (int) cia->pci_err2); + expected = 1; + } + } + process_mcheck_info(vector, la_ptr, regs, "CIA", expected); } diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_irongate.c linux/arch/alpha/kernel/core_irongate.c --- v2.3.42/linux/arch/alpha/kernel/core_irongate.c Wed Dec 15 10:43:16 1999 +++ linux/arch/alpha/kernel/core_irongate.c Mon Feb 7 20:09:05 2000 @@ -351,4 +351,8 @@ hose->mem_space = &iomem_resource; hose->config_space = IRONGATE_CONF; hose->index = 0; + + hose->sg_isa = hose->sg_pci = NULL; + __direct_map_base = 0; + __direct_map_size = 0xffffffff; } diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c --- v2.3.42/linux/arch/alpha/kernel/core_lca.c Tue Nov 23 22:42:20 1999 +++ linux/arch/alpha/kernel/core_lca.c Mon Feb 7 20:09:05 2000 @@ -278,23 +278,51 @@ write_dword: lca_write_config_dword }; +void +lca_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + wmb(); + *(vip)LCA_IOC_TBIA = 0; + mb(); +} + void __init lca_init_arch(void) { struct pci_controler *hose; /* - * Set up the PCI->physical memory translation windows. - * For now, window 1 is disabled. In the future, we may - * want to use it to do scatter/gather DMA. + * Create our single hose. + */ + + pci_isa_hose = hose = alloc_pci_controler(); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = LCA_CONF; + hose->index = 0; + + /* + * Set up the PCI to main memory translation windows. * - * Window 0 goes at 1 GB and is 1 GB large. + * Window 0 is direct access 1GB at 1GB + * Window 1 is scatter-gather 8MB at 8MB (for isa) */ - *(vulp)LCA_IOC_W_BASE0 = 1UL << 33 | LCA_DMA_WIN_BASE; - *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1; + hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); + hose->sg_pci = NULL; + __direct_map_base = 0x40000000; + __direct_map_size = 0x40000000; + + *(vulp)LCA_IOC_W_BASE0 = __direct_map_base | (2UL << 32); + *(vulp)LCA_IOC_W_MASK0 = (__direct_map_size - 1) & 0xfff00000; *(vulp)LCA_IOC_T_BASE0 = 0; - *(vulp)LCA_IOC_W_BASE1 = 0UL; + *(vulp)LCA_IOC_W_BASE1 = hose->sg_isa->dma_base | (3UL << 32); + *(vulp)LCA_IOC_W_MASK1 = (hose->sg_isa->size - 1) & 0xfff00000; + *(vulp)LCA_IOC_T_BASE1 = virt_to_phys(hose->sg_isa->ptes); + + *(vulp)LCA_IOC_TB_ENA = 0x80; + + lca_pci_tbi(hose, 0, -1); /* * Disable PCI parity for now. The NCR53c810 chip has @@ -302,16 +330,6 @@ * data parity errors. */ *(vulp)LCA_IOC_PAR_DIS = 1UL<<5; - - /* - * Create our single hose. - */ - - hose = alloc_pci_controler(); - hose->io_space = &ioport_resource; - hose->mem_space = &iomem_resource; - hose->config_space = LCA_CONF; - hose->index = 0; } /* diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.3.42/linux/arch/alpha/kernel/core_mcpcia.c Fri Jan 21 18:19:15 2000 +++ linux/arch/alpha/kernel/core_mcpcia.c Mon Feb 7 20:09:05 2000 @@ -293,6 +293,14 @@ write_dword: mcpcia_write_config_dword }; +void +mcpcia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + wmb(); + BUG(); + mb(); +} + static int __init mcpcia_probe_hose(int h) { @@ -395,31 +403,36 @@ /* * Set up the PCI->physical memory translation windows. - * For now, windows 1,2 and 3 are disabled. In the - * future, we may want to use them to do scatter/ - * gather DMA. * - * Window 0 goes at 2 GB and is 2 GB large. + * Window 0 is scatter-gather 8MB at 8MB (for isa) + * Window 1 is scatter-gather 128MB at 1GB + * Window 2 is direct access 2GB at 2GB + * ??? We ought to scale window 1 with memory. */ - *(vuip)MCPCIA_W0_BASE(mid) = 1U | (MCPCIA_DMA_WIN_BASE & 0xfff00000U); - *(vuip)MCPCIA_W0_MASK(mid) = (MCPCIA_DMA_WIN_SIZE - 1) & 0xfff00000U; - *(vuip)MCPCIA_T0_BASE(mid) = 0; + hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); + hose->sg_pci = iommu_arena_new(0x40000000, 0x08000000, PAGE_SIZE); + __direct_map_base = 0x80000000; + __direct_map_size = 0x80000000; + + *(vuip)MCPCIA_W0_BASE(mid) = hose->sg_isa->dma_base | 3; + *(vuip)MCPCIA_W0_MASK(mid) = (hose->sg_isa->size - 1) & 0xfff00000; + *(vuip)MCPCIA_T0_BASE(mid) = virt_to_phys(hose->sg_isa->ptes) >> 2; + + *(vuip)MCPCIA_W1_BASE(mid) = hose->sg_pci->dma_base | 3; + *(vuip)MCPCIA_W1_MASK(mid) = (hose->sg_pci->size - 1) & 0xfff00000; + *(vuip)MCPCIA_T1_BASE(mid) = virt_to_phys(hose->sg_pci->ptes) >> 2; + + *(vuip)MCPCIA_W2_BASE(mid) = __direct_map_base | 1; + *(vuip)MCPCIA_W2_MASK(mid) = (__direct_map_size - 1) & 0xfff00000; + *(vuip)MCPCIA_T2_BASE(mid) = 0; - *(vuip)MCPCIA_W1_BASE(mid) = 0x0; - *(vuip)MCPCIA_W2_BASE(mid) = 0x0; *(vuip)MCPCIA_W3_BASE(mid) = 0x0; - *(vuip)MCPCIA_HBASE(mid) = 0x0; - mb(); + mcpcia_pci_tbi(hose, 0, -1); -#if 0 - tmp = *(vuip)MCPCIA_INT_CTL(mid); - printk("mcpcia_startup_hose: INT_CTL was 0x%x\n", tmp); - *(vuip)MCPCIA_INT_CTL(mid) = 1U; + *(vuip)MCPCIA_HBASE(mid) = 0x0; mb(); - tmp = *(vuip)MCPCIA_INT_CTL(mid); -#endif *(vuip)MCPCIA_HAE_MEM(mid) = 0U; mb(); diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_polaris.c linux/arch/alpha/kernel/core_polaris.c --- v2.3.42/linux/arch/alpha/kernel/core_polaris.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/core_polaris.c Mon Feb 7 20:09:05 2000 @@ -197,6 +197,12 @@ hose->mem_space = &iomem_resource; hose->config_space = POLARIS_DENSE_CONFIG_BASE; hose->index = 0; + + hose->sg_isa = hose->sg_pci = NULL; + + /* The I/O window is fixed at 2G @ 2G. */ + __direct_map_base = 0x80000000; + __direct_map_size = 0x80000000; } static inline void diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c --- v2.3.42/linux/arch/alpha/kernel/core_pyxis.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/core_pyxis.c Mon Feb 7 20:09:33 2000 @@ -6,20 +6,22 @@ * Code common to all PYXIS core logic chips. */ -#include #include +#include + +#define __EXTERN_INLINE inline +#include +#include +#undef __EXTERN_INLINE + #include #include #include +#include #include #include -#define __EXTERN_INLINE inline -#include -#include -#undef __EXTERN_INLINE - #include "proto.h" #include "pci_impl.h" @@ -284,6 +286,84 @@ write_dword: pyxis_write_config_dword }; +void +pyxis_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + wmb(); + *(vip)PYXIS_TBIA = 3; /* Flush all locked and unlocked. */ + mb(); +} + +/* + * Pass 1 and 2 have a broken scatter-gather tlb -- it cannot be invalidated. + * To work around this problem, we allocate mappings, and put the chip into + * DMA loopback mode to read a garbage page. This works by causing TLB + * misses, causing old entries to be purged to make room for the new entries + * coming in for the garbage page. + * + * Thanks to NetBSD sources for pointing out this bug. What a pain. + */ + +static unsigned long broken_tbi_addr; + +#define BROKEN_TBI_READS 12 + +static void +pyxis_broken_pci_tbi(struct pci_controler *hose, + dma_addr_t start, dma_addr_t end) +{ + unsigned long flags; + unsigned long bus_addr; + unsigned int ctrl; + long i; + + __save_and_cli(flags); + + /* Put the chip into PCI loopback mode. */ + mb(); + ctrl = *(vuip)PYXIS_CTRL; + *(vuip)PYXIS_CTRL = ctrl | 4; + mb(); + + /* Read from PCI dense memory space at TBI_ADDR, skipping 64k + on each read. This forces SG TLB misses. It appears that + the TLB entries are "not quite LRU", meaning that we need + to read more times than there are actual tags. */ + + bus_addr = broken_tbi_addr; + for (i = 0; i < BROKEN_TBI_READS; ++i, bus_addr += 64*1024) + pyxis_readl(bus_addr); + + /* Restore normal PCI operation. */ + mb(); + *(vuip)PYXIS_CTRL = ctrl; + mb(); + + __restore_flags(flags); +} + +static void +pyxis_enable_broken_tbi(struct pci_iommu_arena *arena) +{ + void *page; + unsigned long *ppte, ofs, pte; + long i, npages; + + page = alloc_bootmem_pages(PAGE_SIZE); + pte = (virt_to_phys(page) >> (PAGE_SHIFT - 1)) | 1; + npages = (BROKEN_TBI_READS + 1) * 64*1024 / PAGE_SIZE; + + ofs = iommu_arena_alloc(arena, npages); + ppte = arena->ptes + ofs; + for (i = 0; i < npages; ++i) + ppte[i] = pte; + + broken_tbi_addr = pyxis_ioremap(arena->dma_base + ofs*PAGE_SIZE); + alpha_mv.mv_pci_tbi = pyxis_broken_pci_tbi; + + printk("PYXIS: Enabling broken tbia workaround.\n"); +} + void __init pyxis_init_arch(void) { @@ -306,84 +386,100 @@ */ temp = *(vuip)PYXIS_ERR_MASK; temp &= ~4; - *(vuip)PYXIS_ERR_MASK = temp; mb(); - temp = *(vuip)PYXIS_ERR_MASK; /* re-read to force write */ + *(vuip)PYXIS_ERR_MASK = temp; + mb(); + *(vuip)PYXIS_ERR_MASK; /* re-read to force write */ + + temp = *(vuip)PYXIS_ERR; + temp |= 0x180; /* master/target abort */ + *(vuip)PYXIS_ERR = temp; + mb(); + *(vuip)PYXIS_ERR; /* re-read to force write */ - temp = *(vuip)PYXIS_ERR ; - temp |= 0x180; /* master/target abort */ - *(vuip)PYXIS_ERR = temp; mb(); - temp = *(vuip)PYXIS_ERR; /* re-read to force write */ + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = PYXIS_CONF; + hose->index = 0; /* - * Set up the PCI->physical memory translation windows. - * For now, windows 2 and 3 are disabled. In the future, we may - * want to use them to do scatter/gather DMA. + * Set up the PCI to main memory translation windows. + * + * Window 0 is scatter-gather 8MB at 8MB (for isa) + * Window 1 is scatter-gather 128MB at 3GB + * Window 2 is direct access 1GB at 1GB + * Window 3 is direct access 1GB at 2GB + * ??? We ought to scale window 1 with memory. * - * Window 0 goes at 2 GB and is 1 GB large. - * Window 1 goes at 3 GB and is 1 GB large. + * We must actually use 2 windows to direct-map the 2GB space, + * because of an idiot-syncrasy of the CYPRESS chip. It may + * respond to a PCI bus address in the last 1MB of the 4GB + * address range. */ - *(vuip)PYXIS_W0_BASE = PYXIS_DMA_WIN0_BASE_DEFAULT | 1U; - *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN0_SIZE_DEFAULT - 1) & 0xfff00000U; - *(vuip)PYXIS_T0_BASE = PYXIS_DMA_WIN0_TRAN_DEFAULT >> 2; - - *(vuip)PYXIS_W1_BASE = PYXIS_DMA_WIN1_BASE_DEFAULT | 1U; - *(vuip)PYXIS_W1_MASK = (PYXIS_DMA_WIN1_SIZE_DEFAULT - 1) & 0xfff00000U; - *(vuip)PYXIS_T1_BASE = PYXIS_DMA_WIN1_TRAN_DEFAULT >> 2; + /* NetBSD hints that page tables must be aligned to 32K due + to a hardware bug. No description of what models affected. */ + hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 32768); + hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, 32768); + __direct_map_base = 0x40000000; + __direct_map_size = 0x80000000; + + *(vuip)PYXIS_W0_BASE = hose->sg_isa->dma_base | 3; + *(vuip)PYXIS_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000; + *(vuip)PYXIS_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2; + + *(vuip)PYXIS_W1_BASE = hose->sg_pci->dma_base | 3; + *(vuip)PYXIS_W1_MASK = (hose->sg_pci->size - 1) & 0xfff00000; + *(vuip)PYXIS_T1_BASE = virt_to_phys(hose->sg_pci->ptes) >> 2; + + *(vuip)PYXIS_W2_BASE = 0x40000000 | 1; + *(vuip)PYXIS_W2_MASK = (0x40000000 - 1) & 0xfff00000; + *(vuip)PYXIS_T2_BASE = 0; + + *(vuip)PYXIS_W3_BASE = 0x80000000 | 1; + *(vuip)PYXIS_W3_MASK = (0x40000000 - 1) & 0xfff00000; + *(vuip)PYXIS_T3_BASE = 0; + + /* Pass 1 and 2 (ie revision <= 1) have a broken TBIA. See the + complete description next to pyxis_broken_pci_tbi for details. */ + if ((*(vuip)PYXIS_REV & 0xff) <= 1) + pyxis_enable_broken_tbi(hose->sg_pci); - *(vuip)PYXIS_W2_BASE = 0x0; - *(vuip)PYXIS_W3_BASE = 0x0; - mb(); + alpha_mv.mv_pci_tbi(hose, 0, -1); /* - * Next, clear the PYXIS_CFG register, which gets used + * Next, clear the PYXIS_CFG register, which gets used * for PCI Config Space accesses. That is the way * we want to use it, and we do not want to depend on * what ARC or SRM might have left behind... */ - { - unsigned int pyxis_cfg, temp; - pyxis_cfg = *(vuip)PYXIS_CFG; mb(); - if (pyxis_cfg != 0) { -#if 1 - printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg); -#endif - *(vuip)PYXIS_CFG = 0; mb(); - temp = *(vuip)PYXIS_CFG; /* re-read to force write */ - } + temp = *(vuip)PYXIS_CFG; + if (temp != 0) { + *(vuip)PYXIS_CFG = 0; + mb(); + *(vuip)PYXIS_CFG; /* re-read to force write */ } /* Zero the HAE. */ *(vuip)PYXIS_HAE_MEM = 0U; mb(); - *(vuip)PYXIS_HAE_MEM; /* re-read to force write */ + *(vuip)PYXIS_HAE_MEM; /* re-read to force write */ *(vuip)PYXIS_HAE_IO = 0; mb(); - *(vuip)PYXIS_HAE_IO; /* re-read to force write */ + *(vuip)PYXIS_HAE_IO; /* re-read to force write */ /* * Finally, check that the PYXIS_CTRL1 has IOA_BEN set for * enabling byte/word PCI bus space(s) access. */ - { - unsigned int ctrl1; - ctrl1 = *(vuip) PYXIS_CTRL1; - if (!(ctrl1 & 1)) { -#if 1 - printk("PYXIS_init: enabling byte/word PCI space\n"); -#endif - *(vuip) PYXIS_CTRL1 = ctrl1 | 1; mb(); - ctrl1 = *(vuip)PYXIS_CTRL1; /* re-read */ - } + temp = *(vuip) PYXIS_CTRL1; + if (!(temp & 1)) { + *(vuip)PYXIS_CTRL1 = temp | 1; + mb(); + *(vuip)PYXIS_CTRL1; /* re-read */ } - - /* - * Create our single hose. - */ - - hose = alloc_pci_controler(); - hose->io_space = &ioport_resource; - hose->mem_space = &iomem_resource; - hose->config_space = PYXIS_CONF; - hose->index = 0; } static inline void @@ -401,6 +497,8 @@ pyxis_machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs) { + int expected; + /* Clear the error before reporting anything. */ mb(); mb(); /* magic */ @@ -409,5 +507,23 @@ wrmces(0x7); mb(); - process_mcheck_info(vector, la_ptr, regs, "PYXIS", mcheck_expected(0)); + expected = mcheck_expected(0); + if (!expected && vector == 0x660) { + struct el_common *com; + struct el_common_EV5_uncorrectable_mcheck *ev5; + struct el_PYXIS_sysdata_mcheck *pyxis; + + com = (void *)la_ptr; + ev5 = (void *)(la_ptr + com->proc_offset); + pyxis = (void *)(la_ptr + com->sys_offset); + + if (com->code == 0x202) { + printk(KERN_CRIT "PYXIS PCI machine check: err0=%08x " + "err1=%08x err2=%08x\n", + (int) pyxis->pci_err0, (int) pyxis->pci_err1, + (int) pyxis->pci_err2); + expected = 1; + } + } + process_mcheck_info(vector, la_ptr, regs, "PYXIS", expected); } diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c --- v2.3.42/linux/arch/alpha/kernel/core_t2.c Tue Nov 23 22:42:20 1999 +++ linux/arch/alpha/kernel/core_t2.c Mon Feb 7 20:09:05 2000 @@ -389,6 +389,10 @@ hose->mem_space = &iomem_resource; hose->config_space = T2_CONF; hose->index = 0; + + hose->sg_isa = hose->sg_pci = NULL; + __direct_map_base = 0x40000000; + __direct_map_size = 0x40000000; } #define SIC_SEIC (1UL << 33) /* System Event Clear */ diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.3.42/linux/arch/alpha/kernel/core_tsunami.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/core_tsunami.c Mon Feb 7 20:09:05 2000 @@ -100,11 +100,11 @@ "pci_addr=0x%p, type1=0x%p)\n", bus, device_fn, where, pci_addr, type1)); - if (hose->first_busno == dev->bus->number) + if (hose->first_busno == dev->bus->number) bus = 0; - *type1 = (bus != 0); + *type1 = (bus != 0); - addr = (bus << 16) | (device_fn << 8) | where; + addr = (bus << 16) | (device_fn << 8) | where; addr |= hose->config_space; *pci_addr = addr; @@ -206,6 +206,23 @@ write_dword: tsunami_write_config_dword }; +void +tsunami_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +{ + tsunami_pchip *pchip = hose->index ? TSUNAMI_pchip1 : TSUNAMI_pchip0; + + wmb(); + + /* We can invalidate up to 8 tlb entries in a go. The flush + matches against <31:16> in the pci address. */ + if (((start ^ end) & 0xffff0000) == 0) + pchip->tlbiv.csr = (start & 0xffff0000) >> 12; + else + pchip->tlbia.csr = 0; + + mb(); +} + #ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI static long tsunami_probe_read(volatile unsigned long *vaddr) @@ -264,6 +281,8 @@ return; hose = alloc_pci_controler(); + if (index == 0) + pci_isa_hose = hose; hose->io_space = alloc_resource(); hose->mem_space = alloc_resource(); @@ -307,27 +326,41 @@ saved_pchip[index].tba[3] = pchip->tba[3].csr; /* - * Set up the PCI->physical memory translation windows. - * For now, windows 1,2 and 3 are disabled. In the future, - * we may want to use them to do scatter/gather DMA. + * Set up the PCI to main memory translation windows. + * + * Window 0 is scatter-gather 8MB at 8MB (for isa) + * Window 1 is scatter-gather 128MB at 3GB + * Window 2 is direct access 1GB at 1GB + * Window 3 is direct access 1GB at 2GB + * ??? We ought to scale window 1 memory. * - * Window 0 goes at 1 GB and is 1 GB large, mapping to 0. - * Window 1 goes at 2 GB and is 1 GB large, mapping to 1GB. + * We must actually use 2 windows to direct-map the 2GB space, + * because of an idiot-syncrasy of the CYPRESS chip. It may + * respond to a PCI bus address in the last 1MB of the 4GB + * address range. */ + hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); + hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, PAGE_SIZE); + __direct_map_base = 0x40000000; + __direct_map_size = 0x80000000; + + pchip->wsba[0].csr = hose->sg_isa->dma_base | 3; + pchip->wsm[0].csr = (hose->sg_isa->size - 1) & 0xfff00000; + pchip->tba[0].csr = virt_to_phys(hose->sg_isa->ptes); + + pchip->wsba[1].csr = hose->sg_pci->dma_base | 3; + pchip->wsm[1].csr = (hose->sg_pci->size - 1) & 0xfff00000; + pchip->tba[1].csr = virt_to_phys(hose->sg_pci->ptes); + + pchip->wsba[2].csr = 0x40000000 | 1; + pchip->wsm[2].csr = (0x40000000 - 1) & 0xfff00000; + pchip->tba[2].csr = 0; + + pchip->wsba[3].csr = 0x80000000 | 1; + pchip->wsm[3].csr = (0x40000000 - 1) & 0xfff00000; + pchip->tba[3].csr = 0; - pchip->wsba[0].csr = TSUNAMI_DMA_WIN0_BASE_DEFAULT | 1UL; - pchip->wsm[0].csr = (TSUNAMI_DMA_WIN0_SIZE_DEFAULT - 1) & - 0xfff00000UL; - pchip->tba[0].csr = TSUNAMI_DMA_WIN0_TRAN_DEFAULT; - - pchip->wsba[1].csr = TSUNAMI_DMA_WIN1_BASE_DEFAULT | 1UL; - pchip->wsm[1].csr = (TSUNAMI_DMA_WIN1_SIZE_DEFAULT - 1) & - 0xfff00000UL; - pchip->tba[1].csr = TSUNAMI_DMA_WIN1_TRAN_DEFAULT; - - pchip->wsba[2].csr = 0; - pchip->wsba[3].csr = 0; - mb(); + tsunami_pci_tbi(hose, 0, -1); } void __init @@ -335,7 +368,7 @@ { #ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI extern asmlinkage void entInt(void); - unsigned long tmp; + unsigned long tmp; /* Ho hum.. init_arch is called before init_IRQ, but we need to be able to handle machine checks. So install the handler now. */ @@ -426,7 +459,7 @@ /* TSUNAMI and TYPHOON can have 2, but might only have 1 (DS10) */ if (TSUNAMI_cchip->csc.csr & 1L<<14) - tsunami_pci_clr_err_1(TSUNAMI_pchip1); + tsunami_pci_clr_err_1(TSUNAMI_pchip1); } void diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.3.42/linux/arch/alpha/kernel/entry.S Tue Jan 11 22:31:36 2000 +++ linux/arch/alpha/kernel/entry.S Wed Feb 9 20:08:09 2000 @@ -32,6 +32,7 @@ #define TASK_ADDR_LIMIT 24 #define TASK_EXEC_DOMAIN 32 #define TASK_NEED_RESCHED 40 +#define TASK_PROCESSOR 100 /* * task flags (must match include/linux/sched.h): @@ -572,12 +573,15 @@ .align 3 ret_from_sys_call: cmovne $26,0,$19 /* $19 = 0 => non-restartable */ - /* check bottom half interrupts */ - ldq $3,bh_active - ldq $4,bh_mask - and $3,$4,$2 - bne $2,handle_bottom_half -ret_from_handle_bh: + ldq $3,TASK_PROCESSOR($8) + lda $4,softirq_state + sll $3,5,$3 + addq $3,$4,$4 + ldq $4,0($4) + sll $4,32,$3 + and $4,$3,$4 + bne $4,handle_softirq +ret_from_softirq: ldq $0,SP_OFF($30) and $0,8,$0 beq $0,restore_all @@ -656,16 +660,16 @@ br ret_from_sys_call .align 3 -handle_bottom_half: +handle_softirq: subq $30,16,$30 stq $19,0($30) /* save syscall nr */ stq $20,8($30) /* and error indication (a3) */ - jsr $26,do_bottom_half + jsr $26,do_softirq ldq $19,0($30) ldq $20,8($30) addq $30,16,$30 - br ret_from_handle_bh - + br ret_from_softirq + .align 3 syscall_error: /* diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.3.42/linux/arch/alpha/kernel/irq.c Wed Dec 8 14:11:24 1999 +++ linux/arch/alpha/kernel/irq.c Wed Feb 9 20:08:09 2000 @@ -377,10 +377,6 @@ /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); -/* This protects BH software state (masks, things like that). */ -atomic_t global_bh_lock = ATOMIC_INIT(0); -atomic_t global_bh_count = ATOMIC_INIT(0); - static void *previous_irqholder = NULL; #define MAXCOUNT 100000000 @@ -401,7 +397,7 @@ */ if (!atomic_read(&global_irq_count)) { if (local_bh_count(cpu) - || !atomic_read(&global_bh_count)) + || !spin_is_locked(&global_bh_lock)) break; } @@ -422,7 +418,7 @@ if (spin_is_locked(&global_irq_lock)) continue; if (!local_bh_count(cpu) - && atomic_read(&global_bh_count)) + && spin_is_locked(&global_bh_lock)) continue; if (spin_trylock(&global_irq_lock)) break; @@ -552,7 +548,7 @@ cpu_data[1].irq_count); printk("bh: %d [%d %d]\n", - atomic_read(&global_bh_count), + spin_is_locked(&global_bh_lock) ? 1 : 0, cpu_data[0].bh_count, cpu_data[1].bh_count); #if 0 @@ -567,35 +563,6 @@ #endif } -static inline void -wait_on_bh(void) -{ - int count = MAXCOUNT; - do { - if (!--count) { - show("wait_on_bh", 0); - count = ~0; - } - /* nothing .. wait for the other bh's to go away */ - barrier(); - } while (atomic_read(&global_bh_count) != 0); -} - -/* - * This is called when we want to synchronize with - * bottom half handlers. We need to wait until - * no other CPU is executing any bottom half handler. - * - * Don't wait if we're already running in an interrupt - * context or are inside a bh handler. - */ -void -synchronize_bh(void) -{ - if (atomic_read(&global_bh_count) && !in_interrupt()) - wait_on_bh(); -} - /* * From its use, I infer that synchronize_irq() stalls a thread until * the effects of a command to an external device are known to have @@ -897,6 +864,7 @@ case 0x98: reason = "processor detected hard error"; break; /* System specific (these are for Alcor, at least): */ + case 0x202: reason = "system detected hard error"; break; case 0x203: reason = "system detected uncorrectable ECC error"; break; case 0x204: reason = "SIO SERR occurred on PCI bus"; break; case 0x205: reason = "parity error detected by CIA"; break; diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/machvec_impl.h linux/arch/alpha/kernel/machvec_impl.h --- v2.3.42/linux/arch/alpha/kernel/machvec_impl.h Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/machvec_impl.h Mon Feb 7 20:09:05 2000 @@ -101,8 +101,7 @@ #define DO_TSUNAMI_IO IO(TSUNAMI,tsunami) #define BUS(which) \ - mv_virt_to_bus: CAT(which,_virt_to_bus), \ - mv_bus_to_virt: CAT(which,_bus_to_virt) + mv_pci_tbi: CAT(which,_pci_tbi) #define DO_APECS_BUS BUS(apecs) #define DO_CIA_BUS BUS(cia) diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.3.42/linux/arch/alpha/kernel/pci.c Fri Jan 21 18:19:15 2000 +++ linux/arch/alpha/kernel/pci.c Mon Feb 7 20:09:05 2000 @@ -40,6 +40,7 @@ */ struct pci_controler *hose_head, **hose_tail = &hose_head; +struct pci_controler *pci_isa_hose; /* * Quirks. diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h --- v2.3.42/linux/arch/alpha/kernel/pci_impl.h Tue Nov 23 22:42:20 1999 +++ linux/arch/alpha/kernel/pci_impl.h Mon Feb 7 20:09:05 2000 @@ -7,7 +7,7 @@ struct pci_dev; struct pci_controler; - +struct pci_iommu_arena; /* * We can't just blindly use 64K for machines with EISA busses; they @@ -125,11 +125,16 @@ /* The hose list. */ extern struct pci_controler *hose_head, **hose_tail; +extern struct pci_controler *pci_isa_hose; extern void common_init_pci(void); extern u8 common_swizzle(struct pci_dev *, u8 *); extern struct pci_controler *alloc_pci_controler(void); extern struct resource *alloc_resource(void); + +extern struct pci_iommu_arena *iommu_arena_new(dma_addr_t, unsigned long, + unsigned long); +extern long iommu_arena_alloc(struct pci_iommu_arena *arena, long n); extern const char *const pci_io_names[]; extern const char *const pci_mem_names[]; diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- v2.3.42/linux/arch/alpha/kernel/pci_iommu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/pci_iommu.c Mon Feb 7 20:09:33 2000 @@ -0,0 +1,531 @@ +/* + * linux/arch/alpha/kernel/pci_iommu.c + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "proto.h" +#include "pci_impl.h" + + +#define DEBUG_ALLOC 0 + +#if DEBUG_ALLOC > 0 +# define DBGA(args...) printk(KERN_DEBUG ##args) +#else +# define DBGA(args...) +#endif +#if DEBUG_ALLOC > 1 +# define DBGA2(args...) printk(KERN_DEBUG ##args) +#else +# define DBGA2(args...) +#endif + + +static inline unsigned long +mk_iommu_pte(unsigned long paddr) +{ + return (paddr >> (PAGE_SHIFT-1)) | 1; +} + +static inline long +calc_npages(long bytes) +{ + return (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; +} + +struct pci_iommu_arena * +iommu_arena_new(dma_addr_t base, unsigned long window_size, + unsigned long align) +{ + unsigned long entries, mem_size, mem_pages; + struct pci_iommu_arena *arena; + + entries = window_size >> PAGE_SHIFT; + mem_size = entries * sizeof(unsigned long); + mem_pages = calc_npages(mem_size); + + arena = alloc_bootmem(sizeof(*arena)); + arena->ptes = __alloc_bootmem(mem_pages * PAGE_SIZE, align, 0); + + spin_lock_init(&arena->lock); + arena->dma_base = base; + arena->size = window_size; + arena->alloc_hint = 0; + + return arena; +} + +long +iommu_arena_alloc(struct pci_iommu_arena *arena, long n) +{ + unsigned long flags; + unsigned long *beg, *p, *end; + long i; + + spin_lock_irqsave(&arena->lock, flags); + + /* Search forward for the first sequence of N empty ptes. */ + beg = arena->ptes; + end = beg + (arena->size >> PAGE_SHIFT); + p = beg + arena->alloc_hint; + i = 0; + while (i < n && p < end) + i = (*p++ == 0 ? i + 1 : 0); + + if (p >= end) { + /* Failure. Assume the hint was wrong and go back to + search from the beginning. */ + p = beg; + i = 0; + while (i < n && p < end) + i = (*p++ == 0 ? i + 1 : 0); + + if (p >= end) { + spin_unlock_irqrestore(&arena->lock, flags); + return -1; + } + } + + /* Success. Mark them all in use, ie not zero. Typically + bit zero is the valid bit, so write ~1 into everything. + The chip specific bits will fill this in with something + kosher when we return. */ + for (p = p - n, i = 0; i < n; ++i) + p[i] = ~1UL; + + arena->alloc_hint = p - beg + n; + spin_unlock_irqrestore(&arena->lock, flags); + + return p - beg; +} + +static void +iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n) +{ + unsigned long *p; + long i; + + p = arena->ptes + ofs; + for (i = 0; i < n; ++i) + p[i] = 0; + arena->alloc_hint = ofs; +} + +/* Map a single buffer of the indicate size for PCI DMA in streaming + mode. The 32-bit PCI bus mastering address to use is returned. + Once the device is given the dma address, the device owns this memory + until either pci_unmap_single or pci_sync_single is performed. */ + +dma_addr_t +pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size) +{ + struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose; + dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + struct pci_iommu_arena *arena; + long npages, dma_ofs, i; + unsigned long paddr; + dma_addr_t ret; + + paddr = virt_to_phys(cpu_addr); + + /* First check to see if we can use the direct map window. */ + if (paddr + size + __direct_map_base - 1 <= max_dma + && paddr + size <= __direct_map_size) { + ret = paddr + __direct_map_base; + + DBGA2("pci_map_single: [%p,%lx] -> direct %x from %p\n", + cpu_addr, size, ret, __builtin_return_address(0)); + + return ret; + } + + /* If the machine doesn't define a pci_tbi routine, we have to + assume it doesn't support sg mapping. */ + if (! alpha_mv.mv_pci_tbi) { + printk(KERN_INFO "pci_map_single failed: no hw sg\n"); + return 0; + } + + arena = hose->sg_pci; + if (!arena || arena->dma_base + arena->size > max_dma) + arena = hose->sg_isa; + + npages = calc_npages((paddr & ~PAGE_MASK) + size); + dma_ofs = iommu_arena_alloc(arena, npages); + if (dma_ofs < 0) { + printk(KERN_INFO "pci_map_single failed: " + "could not allocate dma page tables\n"); + return 0; + } + + paddr &= PAGE_MASK; + for (i = 0; i < npages; ++i, paddr += PAGE_SIZE) + arena->ptes[i + dma_ofs] = mk_iommu_pte(paddr); + + ret = arena->dma_base + dma_ofs * PAGE_SIZE; + ret += (unsigned long)cpu_addr & ~PAGE_MASK; + + /* ??? This shouldn't have been needed, since the entries + we've just modified were not in the iommu tlb. */ + alpha_mv.mv_pci_tbi(hose, ret, ret + size - 1); + + DBGA("pci_map_single: [%p,%lx] np %ld -> sg %x from %p\n", + cpu_addr, size, npages, ret, __builtin_return_address(0)); + + return ret; +} + + +/* Unmap a single streaming mode DMA translation. The DMA_ADDR and + SIZE must match what was provided for in a previous pci_map_single + call. All other usages are undefined. After this call, reads by + the cpu to the buffer are guarenteed to see whatever the device + wrote there. */ + +void +pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size) +{ + struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose; + struct pci_iommu_arena *arena; + long dma_ofs, npages; + + + if (dma_addr >= __direct_map_base + && dma_addr < __direct_map_base + __direct_map_size) { + /* Nothing to do. */ + + DBGA2("pci_unmap_single: direct [%x,%lx] from %p\n", + dma_addr, size, __builtin_return_address(0)); + + return; + } + + arena = hose->sg_pci; + if (!arena || dma_addr < arena->dma_base) + arena = hose->sg_isa; + + dma_ofs = (dma_addr - arena->dma_base) >> PAGE_SHIFT; + if (dma_ofs * PAGE_SIZE >= arena->size) { + printk(KERN_ERR "Bogus pci_unmap_single: dma_addr %x " + " base %x size %x\n", dma_addr, arena->dma_base, + arena->size); + return; + BUG(); + } + + npages = calc_npages((dma_addr & ~PAGE_MASK) + size); + iommu_arena_free(arena, dma_ofs, npages); + alpha_mv.mv_pci_tbi(hose, dma_addr, dma_addr + size - 1); + + DBGA2("pci_unmap_single: sg [%x,%lx] np %ld from %p\n", + dma_addr, size, npages, __builtin_return_address(0)); +} + + +/* Allocate and map kernel buffer using consistent mode DMA for PCI + device. Returns non-NULL cpu-view pointer to the buffer if + successful and sets *DMA_ADDRP to the pci side dma address as well, + else DMA_ADDRP is undefined. */ + +void * +pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp) +{ + void *cpu_addr; + + cpu_addr = kmalloc(size, GFP_ATOMIC); + if (! cpu_addr) { + printk(KERN_INFO "dma_alloc_consistent: " + "kmalloc failed from %p\n", + __builtin_return_address(0)); + /* ??? Really atomic allocation? Otherwise we could play + with vmalloc and sg if we can't find contiguous memory. */ + return NULL; + } + memset(cpu_addr, 0, size); + + *dma_addrp = pci_map_single(pdev, cpu_addr, size); + if (*dma_addrp == 0) { + kfree_s(cpu_addr, size); + return NULL; + } + + DBGA2("dma_alloc_consistent: %lx -> [%p,%x] from %p\n", + size, cpu_addr, *dma_addrp, __builtin_return_address(0)); + + return cpu_addr; +} + + +/* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must + be values that were returned from pci_alloc_consistent. SIZE must + be the same as what as passed into pci_alloc_consistent. + References to the memory and mappings assosciated with CPU_ADDR or + DMA_ADDR past this call are illegal. */ + +void +pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr, + dma_addr_t dma_addr) +{ + pci_unmap_single(pdev, dma_addr, size); + kfree_s(cpu_addr, size); + + DBGA2("dma_free_consistent: [%x,%lx] from %p\n", + dma_addr, size, __builtin_return_address(0)); +} + + +/* Classify the elements of the scatterlist. Write dma_address + of each element with: + 0 : Not mergable. + 1 : Followers all physically adjacent. + [23]: Followers all virtually adjacent. + -1 : Not leader. + Write dma_length of each leader with the combined lengths of + the mergable followers. */ + +static inline void +sg_classify(struct scatterlist *sg, struct scatterlist *end) +{ + unsigned long next_vaddr; + struct scatterlist *leader; + + leader = sg; + leader->dma_address = 0; + leader->dma_length = leader->length; + next_vaddr = (unsigned long)leader->address + leader->length; + + for (++sg; sg < end; ++sg) { + unsigned long addr, len; + addr = (unsigned long) sg->address; + len = sg->length; + + if (next_vaddr == addr) { + sg->dma_address = -1; + leader->dma_address |= 1; + leader->dma_length += len; + } else if (((next_vaddr | addr) & ~PAGE_MASK) == 0) { + sg->dma_address = -1; + leader->dma_address |= 2; + leader->dma_length += len; + } else { + leader = sg; + leader->dma_address = 0; + leader->dma_length = len; + } + + next_vaddr = addr + len; + } +} + +/* Given a scatterlist leader, choose an allocation method and fill + in the blanks. */ + +static inline int +sg_fill(struct scatterlist *leader, struct scatterlist *end, + struct scatterlist *out, struct pci_iommu_arena *arena, + dma_addr_t max_dma) +{ + unsigned long paddr = virt_to_phys(leader->address); + unsigned long size = leader->dma_length; + struct scatterlist *sg; + unsigned long *ptes; + long npages, dma_ofs, i; + + /* If everything is physically contiguous, and the addresses + fall into the direct-map window, use it. */ + if (leader->dma_address < 2 + && paddr + size + __direct_map_base - 1 <= max_dma + && paddr + size <= __direct_map_size) { + out->dma_address = paddr + __direct_map_base; + out->dma_length = size; + + DBGA2("sg_fill: [%p,%lx] -> direct %x\n", + leader->address, size, out->dma_address); + + return 0; + } + + /* Otherwise, we'll use the iommu to make the pages virtually + contiguous. */ + + paddr &= ~PAGE_MASK; + npages = calc_npages(paddr + size); + dma_ofs = iommu_arena_alloc(arena, npages); + if (dma_ofs < 0) + return -1; + + out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr; + out->dma_length = size; + + DBGA("sg_fill: [%p,%lx] -> sg %x\n", + leader->address, size, out->dma_address); + + ptes = &arena->ptes[dma_ofs]; + sg = leader; + do { + paddr = virt_to_phys(sg->address); + npages = calc_npages((paddr & ~PAGE_MASK) + sg->length); + + DBGA(" (%ld) [%p,%x]\n", + sg - leader, sg->address, sg->length); + + paddr &= PAGE_MASK; + for (i = 0; i < npages; ++i, paddr += PAGE_SIZE) + *ptes++ = mk_iommu_pte(paddr); + + ++sg; + } while (sg < end && sg->dma_address == -1); + + return 1; +} + +/* TODO: Only use the iommu when it helps. Non-mergable scatterlist + entries might as well use direct mappings. */ + +int +pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents) +{ + struct scatterlist *start, *end, *out; + struct pci_controler *hose; + struct pci_iommu_arena *arena; + dma_addr_t max_dma, fstart, fend; + + /* If pci_tbi is not available, we must not be able to control + an iommu. Direct map everything, no merging. */ + if (! alpha_mv.mv_pci_tbi) { + for (end = sg + nents; sg < end; ++sg) { + sg->dma_address = virt_to_bus(sg->address); + sg->dma_length = sg->length; + } + return nents; + } + + /* Fast path single entry scatterlists. */ + if (nents == 1) { + sg->dma_length = sg->length; + sg->dma_address + = pci_map_single(pdev, sg->address, sg->length); + return sg->dma_address != 0; + } + + hose = pdev ? pdev->sysdata : pci_isa_hose; + max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + arena = hose->sg_pci; + if (!arena || arena->dma_base + arena->size > max_dma) + arena = hose->sg_isa; + start = sg; + end = sg + nents; + fstart = -1; + fend = 0; + + /* First, prepare information about the entries. */ + sg_classify(sg, end); + + /* Second, iterate over the scatterlist leaders and allocate + dma space as needed. */ + for (out = sg; sg < end; ++sg) { + int ret; + + if (sg->dma_address == -1) + continue; + + ret = sg_fill(sg, end, out, arena, max_dma); + if (ret < 0) + goto error; + else if (ret > 0) { + dma_addr_t ts, te; + + ts = out->dma_address; + te = ts + out->dma_length - 1; + if (fstart > ts) + fstart = ts; + if (fend < te) + fend = te; + } + out++; + } + + /* ??? This shouldn't have been needed, since the entries + we've just modified were not in the iommu tlb. */ + if (fend) + alpha_mv.mv_pci_tbi(hose, fstart, fend); + + if (out - start == 0) + printk(KERN_INFO "pci_map_sg failed: no entries?\n"); + + return out - start; + +error: + printk(KERN_INFO "pci_map_sg failed: " + "could not allocate dma page tables\n"); + + /* Some allocation failed while mapping the scatterlist + entries. Unmap them now. */ + if (out > start) + pci_unmap_sg(pdev, start, out - start); + return 0; +} + + +/* Unmap a set of streaming mode DMA translations. Again, cpu read + rules concerning calls here are the same as for pci_unmap_single() + above. */ + +void +pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents) +{ + struct pci_controler *hose; + struct pci_iommu_arena *arena; + struct scatterlist *end; + dma_addr_t max_dma; + dma_addr_t fstart, fend; + + if (! alpha_mv.mv_pci_tbi) + return; + + hose = pdev ? pdev->sysdata : pci_isa_hose; + max_dma = pdev ? pdev->dma_mask : 0x00ffffff; + arena = hose->sg_pci; + if (!arena || arena->dma_base + arena->size > max_dma) + arena = hose->sg_isa; + fstart = -1; + fend = 0; + + for (end = sg + nents; sg < end; ++sg) { + unsigned long addr, size; + + addr = sg->dma_address; + size = sg->dma_length; + + if (addr >= __direct_map_base + && addr < __direct_map_base + __direct_map_size) { + /* Nothing to do. */ + DBGA2("pci_unmap_sg: direct [%lx,%lx]\n", addr, size); + } else { + long npages, ofs; + dma_addr_t tend; + + npages = calc_npages((addr & ~PAGE_MASK) + size); + ofs = (addr - arena->dma_base) >> PAGE_SHIFT; + iommu_arena_free(arena, ofs, npages); + + tend = addr + size - 1; + if (fstart > addr) + fstart = addr; + if (fend < tend) + fend = tend; + + DBGA2("pci_unmap_sg: sg [%lx,%lx]\n", addr, size); + } + } + if (fend) + alpha_mv.mv_pci_tbi(hose, fstart, fend); +} diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.3.42/linux/arch/alpha/kernel/proto.h Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/proto.h Mon Feb 7 20:09:05 2000 @@ -9,55 +9,65 @@ struct pt_regs; struct task_struct; struct pci_dev; +struct pci_controler; /* core_apecs.c */ extern struct pci_ops apecs_pci_ops; extern void apecs_init_arch(void); extern void apecs_pci_clr_err(void); extern void apecs_machine_check(u64, u64, struct pt_regs *); +extern void apecs_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); /* core_cia.c */ extern struct pci_ops cia_pci_ops; extern void cia_init_arch(void); extern void cia_machine_check(u64, u64, struct pt_regs *); +extern void cia_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); /* core_irongate.c */ extern struct pci_ops irongate_pci_ops; extern int irongate_pci_clr_err(void); extern void irongate_init_arch(void); extern void irongate_machine_check(u64, u64, struct pt_regs *); +#define irongate_pci_tbi ((void *)0) /* core_lca.c */ extern struct pci_ops lca_pci_ops; extern void lca_init_arch(void); extern void lca_machine_check(u64, u64, struct pt_regs *); +extern void lca_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); /* core_mcpcia.c */ extern struct pci_ops mcpcia_pci_ops; extern void mcpcia_init_arch(void); extern void mcpcia_init_hoses(void); extern void mcpcia_machine_check(u64, u64, struct pt_regs *); +extern void mcpcia_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); /* core_polaris.c */ extern struct pci_ops polaris_pci_ops; extern void polaris_init_arch(void); extern void polaris_machine_check(u64, u64, struct pt_regs *); +#define polaris_pci_tbi ((void *)0) /* core_pyxis.c */ extern struct pci_ops pyxis_pci_ops; extern void pyxis_init_arch(void); extern void pyxis_machine_check(u64, u64, struct pt_regs *); +extern void pyxis_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); /* core_t2.c */ extern struct pci_ops t2_pci_ops; extern void t2_init_arch(void); extern void t2_machine_check(u64, u64, struct pt_regs *); +#define t2_pci_tbi ((void *)0) /* core_tsunami.c */ extern struct pci_ops tsunami_pci_ops; extern void tsunami_init_arch(void); extern void tsunami_kill_arch(int); extern void tsunami_machine_check(u64, u64, struct pt_regs *); +extern void tsunami_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); /* setup.c */ extern unsigned long srm_hae; diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/semaphore.c linux/arch/alpha/kernel/semaphore.c --- v2.3.42/linux/arch/alpha/kernel/semaphore.c Thu Aug 26 13:05:34 1999 +++ linux/arch/alpha/kernel/semaphore.c Mon Feb 7 20:09:05 2000 @@ -36,7 +36,9 @@ * critical part is the inline stuff in * where we want to avoid any extra jumps and calls. */ -void __up(struct semaphore *sem) + +void +__up(struct semaphore *sem) { wake_one_more(sem); wake_up(&sem->wait); @@ -63,7 +65,7 @@ #define DOWN_VAR \ struct task_struct *tsk = current; \ wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); + init_waitqueue_entry(&wait, tsk) #define DOWN_HEAD(task_state) \ \ @@ -92,23 +94,27 @@ tsk->state = (task_state); \ } \ tsk->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); + remove_wait_queue(&sem->wait, &wait) -void __down(struct semaphore * sem) +void +__down(struct semaphore * sem) { - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) + DOWN_VAR; + DOWN_HEAD(TASK_UNINTERRUPTIBLE); + if (waking_non_zero(sem)) break; schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) + + DOWN_TAIL(TASK_UNINTERRUPTIBLE); } -int __down_interruptible(struct semaphore * sem) +int +__down_interruptible(struct semaphore * sem) { int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) + DOWN_VAR; + DOWN_HEAD(TASK_INTERRUPTIBLE); ret = waking_non_zero_interruptible(sem, tsk); if (ret) @@ -119,11 +125,149 @@ break; } schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) + + DOWN_TAIL(TASK_INTERRUPTIBLE); return ret; } -int __down_trylock(struct semaphore * sem) +int +__down_trylock(struct semaphore * sem) { return waking_non_zero_trylock(sem); +} + + +/* + * RW Semaphores + */ + +void +__down_read(struct rw_semaphore *sem, int count) +{ + long tmp; + DOWN_VAR; + + retry_down: + if (count < 0) { + /* Wait for the lock to become unbiased. Readers + are non-exclusive. */ + + /* This takes care of granting the lock. */ + up_read(sem); + + add_wait_queue(&sem->wait, &wait); + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->count >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + __asm __volatile ( + " mb\n" + "1: ldl_l %0,%1\n" + " subl %0,1,%2\n" + " subl %0,1,%0\n" + " stl_c %2,%1\n" + " bne %2,2f\n" + ".section .text2,\"ax\"\n" + "2: br 1b\n" + ".previous" + : "=r"(count), "=m"(sem->count), "=r"(tmp) + : : "memory"); + if (count <= 0) + goto retry_down; + } else { + add_wait_queue(&sem->wait, &wait); + + while (1) { + if (test_and_clear_bit(0, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if ((sem->granted & 1) == 0) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + } +} + +void +__down_write(struct rw_semaphore *sem, int count) +{ + long tmp; + DOWN_VAR; + + retry_down: + if (count + RW_LOCK_BIAS < 0) { + up_write(sem); + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, (TASK_UNINTERRUPTIBLE + | TASK_EXCLUSIVE)); + if (sem->count >= RW_LOCK_BIAS) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + __asm __volatile ( + " mb\n" + "1: ldl_l %0,%1\n" + " ldah %2,%3(%0)\n" + " ldah %0,%3(%0)\n" + " stl_c %2,%1\n" + " bne %2,2f\n" + ".section .text2,\"ax\"\n" + "2: br 1b\n" + ".previous" + : "=r"(count), "=m"(sem->count), "=r"(tmp) + : "i"(-(RW_LOCK_BIAS >> 16)) + : "memory"); + if (count != 0) + goto retry_down; + } else { + /* Put ourselves at the end of the list. */ + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); + + while (1) { + if (test_and_clear_bit(1, &sem->granted)) + break; + set_task_state(tsk, (TASK_UNINTERRUPTIBLE + | TASK_EXCLUSIVE)); + if ((sem->granted & 2) == 0) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* If the lock is currently unbiased, awaken the sleepers. + FIXME: This wakes up the readers early in a bit of a + stampede -> bad! */ + if (sem->count >= 0) + wake_up(&sem->wait); + } +} + +void +__do_rwsem_wake(struct rw_semaphore *sem, int readers) +{ + if (readers) { + if (test_and_set_bit(0, &sem->granted)) + BUG(); + wake_up(&sem->wait); + } else { + if (test_and_set_bit(1, &sem->granted)) + BUG(); + wake_up(&sem->write_bias_wait); + } } diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.3.42/linux/arch/alpha/kernel/setup.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/setup.c Mon Feb 7 20:09:33 2000 @@ -96,6 +96,13 @@ orig_video_points: 16 }; +/* + * The direct map I/O window, if any. This should be the same + * for all busses, since it's used by virt_to_bus. + */ + +unsigned long __direct_map_base; +unsigned long __direct_map_size; /* * Declare all of the machine vectors. @@ -225,15 +232,8 @@ max_low_pfn = end; } - /* Enforce maximum of 2GB even if there is more. Blah. */ - if (max_low_pfn > PFN_MAX) - max_low_pfn = PFN_MAX; - printk("max_low_pfn %ld\n", max_low_pfn); - /* Find the end of the kernel memory. */ start_pfn = PFN_UP(virt_to_phys(_end)); - printk("_end %p, start_pfn %ld\n", _end, start_pfn); - bootmap_start = -1; try_again: @@ -243,7 +243,6 @@ /* We need to know how many physically contigous pages we'll need for the bootmap. */ bootmap_pages = bootmem_bootmap_pages(max_low_pfn); - printk("bootmap size: %ld pages\n", bootmap_pages); /* Now find a good region where to allocate the bootmap. */ for_each_mem_cluster(memdesc, cluster, i) { @@ -261,8 +260,6 @@ if (end > max_low_pfn) end = max_low_pfn; if (end - start >= bootmap_pages) { - printk("allocating bootmap in area %ld:%ld\n", - start, start+bootmap_pages); bootmap_start = start; break; } @@ -270,8 +267,6 @@ if (bootmap_start == -1) { max_low_pfn >>= 1; - printk("bootmap area not found now trying with %ld pages\n", - max_low_pfn); goto try_again; } @@ -304,8 +299,6 @@ /* Reserve the bootmap memory. */ reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size); - printk("reserving bootmap %ld:%ld\n", bootmap_start, - bootmap_start + PFN_UP(bootmap_size)); #ifdef CONFIG_BLK_DEV_INITRD initrd_start = INITRD_START; @@ -328,27 +321,26 @@ #endif /* CONFIG_BLK_DEV_INITRD */ } -int __init page_is_ram(unsigned long pfn) +int __init +page_is_ram(unsigned long pfn) { struct memclust_struct * cluster; struct memdesc_struct * memdesc; int i; - memdesc = (struct memdesc_struct *) (hwrpb->mddt_offset + (unsigned long) hwrpb); + memdesc = (struct memdesc_struct *) + (hwrpb->mddt_offset + (unsigned long) hwrpb); for_each_mem_cluster(memdesc, cluster, i) { if (pfn >= cluster->start_pfn && - pfn < cluster->start_pfn + cluster->numpages) - { - if (cluster->usage & 3) - return 0; - else - return 1; + pfn < cluster->start_pfn + cluster->numpages) { + return (cluster->usage & 3) ? 0 : 1; } } return 0; } + #undef PFN_UP #undef PFN_DOWN #undef PFN_PHYS @@ -369,8 +361,7 @@ /* Hack for Jensen... since we're restricted to 8 or 16 chars for boot flags depending on the boot mode, we need some shorthand. - This should do for installation. Later we'll add other - abbreviations as well... */ + This should do for installation. */ if (strcmp(COMMAND_LINE, "INSTALL") == 0) { strcpy(command_line, "root=/dev/fd0 load_ramdisk=1"); } else { diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.3.42/linux/arch/alpha/kernel/smp.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/smp.c Wed Feb 9 19:33:13 2000 @@ -51,9 +51,9 @@ } ipi_data[NR_CPUS] __cacheline_aligned; enum ipi_message_type { - IPI_RESCHEDULE, - IPI_CALL_FUNC, - IPI_CPU_STOP, + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_CPU_STOP, }; spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; @@ -70,7 +70,7 @@ int smp_threads_ready; /* True once the per process idle is forked. */ cycles_t cacheflush_time; -int cpu_number_map[NR_CPUS]; +int __cpu_number_map[NR_CPUS]; int __cpu_logical_map[NR_CPUS]; extern void calibrate_delay(void); @@ -426,13 +426,13 @@ if (fork_by_hand() < 0) panic("failed fork for CPU %d", cpuid); - idle = init_task.prev_task; - if (!idle) - panic("No idle process for CPU %d", cpuid); + idle = init_task.prev_task; + if (!idle) + panic("No idle process for CPU %d", cpuid); idle->processor = cpuid; __cpu_logical_map[cpunum] = cpuid; - cpu_number_map[cpuid] = cpunum; + __cpu_number_map[cpuid] = cpunum; idle->has_cpu = 1; /* we schedule the first task manually */ del_from_runqueue(idle); @@ -461,7 +461,7 @@ /* we must invalidate our stuff as we failed to boot the CPU */ __cpu_logical_map[cpunum] = -1; - cpu_number_map[cpuid] = -1; + __cpu_number_map[cpuid] = -1; /* the idle task is local to us so free it as we don't use it */ free_task_struct(idle); @@ -534,11 +534,11 @@ unsigned long bogosum; /* Take care of some initial bookkeeping. */ - memset(cpu_number_map, -1, sizeof(cpu_number_map)); + memset(__cpu_number_map, -1, sizeof(__cpu_number_map)); memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map)); memset(ipi_data, 0, sizeof(ipi_data)); - cpu_number_map[smp_boot_cpuid] = 0; + __cpu_number_map[smp_boot_cpuid] = 0; __cpu_logical_map[0] = smp_boot_cpuid; current->processor = smp_boot_cpuid; @@ -554,7 +554,7 @@ /* Nothing to do on a UP box, or when told not to. */ if (smp_num_probed == 1 || max_cpus == 0) { - printk(KERN_INFO "SMP mode deactivated.\n"); + printk(KERN_INFO "SMP mode deactivated.\n"); return; } @@ -565,7 +565,7 @@ if (i == smp_boot_cpuid) continue; - if (((cpu_present_mask >> i) & 1) == 0) + if (((cpu_present_mask >> i) & 1) == 0) continue; if (smp_boot_one_cpu(i, cpu_count)) @@ -580,10 +580,10 @@ } bogosum = 0; - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { if (cpu_present_mask & (1L << i)) bogosum += cpu_data[i].loops_per_sec; - } + } printk(KERN_INFO "SMP: Total of %d processors activated " "(%lu.%02lu BogoMIPS).\n", cpu_count, (bogosum + 2500) / 500000, @@ -605,7 +605,7 @@ extern void update_one_process(struct task_struct *p, unsigned long ticks, - unsigned long user, unsigned long system, + unsigned long user, unsigned long system, int cpu); void @@ -626,13 +626,13 @@ irq_enter(cpu, TIMER_IRQ); update_one_process(current, 1, user, !user, cpu); - if (current->pid) { - if (--current->counter <= 0) { + if (current->pid) { + if (--current->counter <= 0) { current->counter = 0; - current->need_resched = 1; - } + current->need_resched = 1; + } - if (user) { + if (user) { if (current->priority < DEF_PRIORITY) { kstat.cpu_nice++; kstat.per_cpu_nice[cpu]++; @@ -640,11 +640,11 @@ kstat.cpu_user++; kstat.per_cpu_user[cpu]++; } - } else { + } else { kstat.cpu_system++; kstat.per_cpu_system[cpu]++; - } - } + } + } data->prof_counter = data->prof_multiplier; irq_exit(cpu, TIMER_IRQ); @@ -722,7 +722,7 @@ return -EBUSY; while (*(void **)lock) - schedule(); + barrier(); goto again; } diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c --- v2.3.42/linux/arch/alpha/kernel/sys_jensen.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/sys_jensen.c Mon Feb 7 20:09:05 2000 @@ -111,11 +111,20 @@ } static void +jensen_init_arch(void) +{ + __direct_map_base = 0; + __direct_map_size = 0xffffffff; +} + +static void jensen_machine_check (u64 vector, u64 la, struct pt_regs *regs) { printk(KERN_CRIT "Machine check\n"); } +#define jensen_pci_tbi ((void*)0) + /* * The System Vector @@ -136,7 +145,7 @@ ack_irq: common_ack_irq, device_interrupt: jensen_device_interrupt, - init_arch: NULL, + init_arch: jensen_init_arch, init_irq: jensen_init_irq, init_pit: common_init_pit, init_pci: NULL, diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c --- v2.3.42/linux/arch/alpha/kernel/sys_sio.c Thu Jan 6 12:57:47 2000 +++ linux/arch/alpha/kernel/sys_sio.c Mon Feb 7 20:09:05 2000 @@ -55,52 +55,6 @@ } static inline void __init -xl_init_arch(void) -{ - struct pci_controler *hose; - - /* - * Set up the PCI->physical memory translation windows. For - * the XL we *must* use both windows, in order to maximize the - * amount of physical memory that can be used to DMA from the - * ISA bus, and still allow PCI bus devices access to all of - * host memory. - * - * See for window bases and sizes. - * - * This restriction due to the true XL motherboards' 82379AB SIO - * PCI<->ISA bridge chip which passes only 27 bits of address... - */ - - *(vuip)APECS_IOC_PB1R = 1<<19 | (APECS_XL_DMA_WIN1_BASE & 0xfff00000U); - *(vuip)APECS_IOC_PM1R = (APECS_XL_DMA_WIN1_SIZE - 1) & 0xfff00000U; - *(vuip)APECS_IOC_TB1R = 0; - - *(vuip)APECS_IOC_PB2R = 1<<19 | (APECS_XL_DMA_WIN2_BASE & 0xfff00000U); - *(vuip)APECS_IOC_PM2R = (APECS_XL_DMA_WIN2_SIZE - 1) & 0xfff00000U; - *(vuip)APECS_IOC_TB2R = 0; - - /* - * Finally, clear the HAXR2 register, which gets used for PCI - * Config Space accesses. That is the way we want to use it, - * and we do not want to depend on what ARC or SRM might have - * left behind... - */ - - *(vuip)APECS_IOC_HAXR2 = 0; mb(); - - /* - * Create our single hose. - */ - - hose = alloc_pci_controler(); - hose->io_space = &ioport_resource; - hose->mem_space = &iomem_resource; - hose->config_space = LCA_CONF; - hose->index = 0; -} - -static inline void __init alphabook1_init_arch(void) { /* The AlphaBook1 has LCD video fixed at 800x600, @@ -448,7 +402,7 @@ DO_EV4_MMU, DO_DEFAULT_RTC, DO_APECS_IO, - BUS(apecs_xl), + BUS(apecs), machine_check: apecs_machine_check, max_dma_address: ALPHA_XL_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, @@ -460,7 +414,7 @@ ack_irq: common_ack_irq, device_interrupt: isa_device_interrupt, - init_arch: xl_init_arch, + init_arch: lca_init_arch, init_irq: sio_init_irq, init_pit: common_init_pit, init_pci: noname_init_pci, diff -u --recursive --new-file v2.3.42/linux/arch/alpha/lib/semaphore.S linux/arch/alpha/lib/semaphore.S --- v2.3.42/linux/arch/alpha/lib/semaphore.S Wed Jan 27 10:18:03 1999 +++ linux/arch/alpha/lib/semaphore.S Mon Feb 7 20:09:05 2000 @@ -1,7 +1,7 @@ /* * linux/arch/alpha/lib/semaphore.S * - * Copyright (C) 1999 Richard Henderson + * Copyright (C) 1999, 2000 Richard Henderson */ /* @@ -181,3 +181,168 @@ lda $30, 20*8($30) ret $31, ($28), 0 .end __up_wakeup + +/* __down_read_failed takes the semaphore in $24, count in $25; + clobbers $24, $25 and $28. */ + + .globl __down_read_failed + .ent __down_read_failed +__down_read_failed: + ldgp $29,0($27) + lda $30, -18*8($30) + stq $28, 0*8($30) + stq $0, 1*8($30) + stq $1, 2*8($30) + stq $2, 3*8($30) + stq $3, 4*8($30) + stq $4, 5*8($30) + stq $5, 6*8($30) + stq $6, 7*8($30) + stq $7, 8*8($30) + stq $16, 9*8($30) + stq $17, 10*8($30) + stq $18, 11*8($30) + stq $19, 12*8($30) + stq $20, 13*8($30) + stq $21, 14*8($30) + stq $22, 15*8($30) + stq $23, 16*8($30) + stq $26, 17*8($30) + .frame $30, 18*8, $28 + .prologue 1 + + mov $24, $16 + mov $25, $17 + jsr __down_read + + ldq $28, 0*8($30) + ldq $0, 1*8($30) + ldq $1, 2*8($30) + ldq $2, 3*8($30) + ldq $3, 4*8($30) + ldq $4, 5*8($30) + ldq $5, 6*8($30) + ldq $6, 7*8($30) + ldq $7, 8*8($30) + ldq $16, 9*8($30) + ldq $17, 10*8($30) + ldq $18, 11*8($30) + ldq $19, 12*8($30) + ldq $20, 13*8($30) + ldq $21, 14*8($30) + ldq $22, 15*8($30) + ldq $23, 16*8($30) + ldq $26, 17*8($30) + lda $30, 18*8($30) + ret $31, ($28), 0 + .end __down_read_failed + +/* __down_write_failed takes the semaphore in $24, count in $25; + clobbers $24, $25 and $28. */ + + .globl __down_write_failed + .ent __down_write_failed +__down_write_failed: + ldgp $29,0($27) + lda $30, -20*8($30) + stq $28, 0*8($30) + stq $0, 1*8($30) + stq $1, 2*8($30) + stq $2, 3*8($30) + stq $3, 4*8($30) + stq $4, 5*8($30) + stq $5, 6*8($30) + stq $6, 7*8($30) + stq $7, 8*8($30) + stq $16, 9*8($30) + stq $17, 10*8($30) + stq $18, 11*8($30) + stq $19, 12*8($30) + stq $20, 13*8($30) + stq $21, 14*8($30) + stq $22, 15*8($30) + stq $23, 16*8($30) + stq $26, 17*8($30) + .frame $30, 18*8, $28 + .prologue 1 + + mov $24, $16 + mov $25, $17 + jsr __down_write + + ldq $28, 0*8($30) + ldq $0, 1*8($30) + ldq $1, 2*8($30) + ldq $2, 3*8($30) + ldq $3, 4*8($30) + ldq $4, 5*8($30) + ldq $5, 6*8($30) + ldq $6, 7*8($30) + ldq $7, 8*8($30) + ldq $16, 9*8($30) + ldq $17, 10*8($30) + ldq $18, 11*8($30) + ldq $19, 12*8($30) + ldq $20, 13*8($30) + ldq $21, 14*8($30) + ldq $22, 15*8($30) + ldq $23, 16*8($30) + ldq $26, 17*8($30) + lda $30, 18*8($30) + ret $31, ($28), 0 + .end __down_write_failed + +/* __rwsem_wake takes the semaphore in $24, readers in $25; + clobbers $24, $25, and $28. */ + + .globl __rwsem_wake + .ent __rwsem_wake +__rwsem_wake: + ldgp $29,0($27) + lda $30, -18*8($30) + stq $28, 0*8($30) + stq $0, 1*8($30) + stq $1, 2*8($30) + stq $2, 3*8($30) + stq $3, 4*8($30) + stq $4, 5*8($30) + stq $5, 6*8($30) + stq $6, 7*8($30) + stq $7, 8*8($30) + stq $16, 9*8($30) + stq $17, 10*8($30) + stq $18, 11*8($30) + stq $19, 12*8($30) + stq $20, 13*8($30) + stq $21, 14*8($30) + stq $22, 15*8($30) + stq $23, 16*8($30) + stq $26, 17*8($30) + .frame $30, 18*8, $28 + .prologue 1 + + mov $24, $16 + mov $25, $17 + jsr __do_rwsem_wake + + ldq $28, 0*8($30) + ldq $0, 1*8($30) + ldq $1, 2*8($30) + ldq $2, 3*8($30) + ldq $3, 4*8($30) + ldq $4, 5*8($30) + ldq $5, 6*8($30) + ldq $6, 7*8($30) + ldq $7, 8*8($30) + ldq $16, 9*8($30) + ldq $17, 10*8($30) + ldq $18, 11*8($30) + ldq $19, 12*8($30) + ldq $20, 13*8($30) + ldq $21, 14*8($30) + ldq $22, 15*8($30) + ldq $23, 16*8($30) + ldq $26, 17*8($30) + lda $30, 18*8($30) + ret $31, ($28), 0 + .end __rwsem_wake diff -u --recursive --new-file v2.3.42/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.3.42/linux/arch/alpha/mm/init.c Fri Jan 21 18:19:15 2000 +++ linux/arch/alpha/mm/init.c Wed Feb 9 20:08:09 2000 @@ -34,7 +34,6 @@ static unsigned long totalram_pages; extern void die_if_kernel(char *,struct pt_regs *,long); -extern void show_net_buffers(void); struct thread_struct original_pcb; @@ -173,9 +172,6 @@ printk("%ld pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } static inline unsigned long @@ -195,7 +191,7 @@ { unsigned long newptbr; unsigned long original_pcb_ptr; - unsigned int zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; unsigned long dma_pfn, high_pfn; dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; diff -u --recursive --new-file v2.3.42/linux/arch/alpha/vmlinux.lds linux/arch/alpha/vmlinux.lds --- v2.3.42/linux/arch/alpha/vmlinux.lds Tue Aug 31 17:29:12 1999 +++ linux/arch/alpha/vmlinux.lds Mon Feb 7 20:09:05 2000 @@ -82,4 +82,6 @@ .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } + + /DISCARD/ : { *(.text.exit) *(.data.exit) } } diff -u --recursive --new-file v2.3.42/linux/arch/arm/def-configs/a5k linux/arch/arm/def-configs/a5k --- v2.3.42/linux/arch/arm/def-configs/a5k Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/def-configs/a5k Sun Feb 6 17:45:25 2000 @@ -167,6 +167,11 @@ # CONFIG_FTAPE is not set # CONFIG_DRM is not set # CONFIG_DRM_TDFX is not set + +# +# PCMCIA character device support +# +# CONFIG_PCMCIA_SERIAL_CS is not set # CONFIG_AGP is not set # @@ -322,6 +327,11 @@ # Wan interfaces # # CONFIG_WAN is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set # # SCSI support diff -u --recursive --new-file v2.3.42/linux/arch/arm/def-configs/footbridge linux/arch/arm/def-configs/footbridge --- v2.3.42/linux/arch/arm/def-configs/footbridge Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/def-configs/footbridge Sun Feb 6 17:45:25 2000 @@ -54,6 +54,7 @@ CONFIG_PARPORT=y CONFIG_PARPORT_PC=y CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_PCMCIA is not set # CONFIG_PARPORT_ARC is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set @@ -264,6 +265,12 @@ # CONFIG_DRM_TDFX is not set # +# PCMCIA character device support +# +# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_AGP is not set + +# # Support for USB # CONFIG_USB=m @@ -495,6 +502,11 @@ # Wan interfaces # # CONFIG_WAN is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set # # SCSI support diff -u --recursive --new-file v2.3.42/linux/arch/arm/def-configs/rpc linux/arch/arm/def-configs/rpc --- v2.3.42/linux/arch/arm/def-configs/rpc Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/def-configs/rpc Sun Feb 6 17:45:25 2000 @@ -50,6 +50,7 @@ CONFIG_PARPORT=y CONFIG_PARPORT_PC=y # CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_PCMCIA is not set # CONFIG_PARPORT_ARC is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set @@ -176,6 +177,11 @@ # CONFIG_FTAPE is not set # CONFIG_DRM is not set # CONFIG_DRM_TDFX is not set + +# +# PCMCIA character device support +# +# CONFIG_PCMCIA_SERIAL_CS is not set # CONFIG_AGP is not set CONFIG_RPCMOUSE=y @@ -347,6 +353,11 @@ # Wan interfaces # # CONFIG_WAN is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set # # SCSI support diff -u --recursive --new-file v2.3.42/linux/arch/arm/defconfig linux/arch/arm/defconfig --- v2.3.42/linux/arch/arm/defconfig Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/defconfig Sun Feb 6 17:45:25 2000 @@ -54,6 +54,7 @@ CONFIG_PARPORT=y CONFIG_PARPORT_PC=y CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_PCMCIA is not set # CONFIG_PARPORT_ARC is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set @@ -262,6 +263,11 @@ # CONFIG_FTAPE is not set # CONFIG_DRM is not set # CONFIG_DRM_TDFX is not set + +# +# PCMCIA character device support +# +# CONFIG_PCMCIA_SERIAL_CS is not set # CONFIG_AGP is not set # @@ -496,6 +502,11 @@ # Wan interfaces # # CONFIG_WAN is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set # # SCSI support diff -u --recursive --new-file v2.3.42/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.3.42/linux/arch/arm/kernel/Makefile Mon Dec 20 18:48:21 1999 +++ linux/arch/arm/kernel/Makefile Sun Feb 6 17:45:25 2000 @@ -16,9 +16,9 @@ ISA_DMA_OBJS += dma-isa.o endif -O_OBJS_arc = dma-arc.o iic.o fiq.o oldlatches.o -O_OBJS_a5k = dma-a5k.o iic.o fiq.o -O_OBJS_rpc = dma-rpc.o iic.o fiq.o +O_OBJS_arc = dma-arc.o iic.o fiq.o time-acorn.o oldlatches.o +O_OBJS_a5k = dma-a5k.o iic.o fiq.o time-acorn.o +O_OBJS_rpc = dma-rpc.o iic.o fiq.o time-acorn.o O_OBJS_ebsa110 = dma-dummy.o O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS) isa.o O_OBJS_nexuspci = dma-dummy.o diff -u --recursive --new-file v2.3.42/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.3.42/linux/arch/arm/kernel/bios32.c Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/kernel/bios32.c Sun Feb 6 17:45:25 2000 @@ -381,7 +381,7 @@ * Assign any unassigned resources. Note that we really ought to * have min/max stuff here - max mem address is 0x0fffffff */ - pci_assign_unassigned_resources(hw_pci->io_start, hw_pci->mem_start); + pci_assign_unassigned_resources(); pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq); pci_set_bus_ranges(); @@ -404,17 +404,34 @@ return str; } -/* - * Assign new address to PCI resource. We hope our resource information - * is complete. - * - * Expects start=0, end=size-1, flags=resource type. - */ -int pci_assign_resource(struct pci_dev *dev, int i) +void pcibios_align_resource(void *data, struct resource *res, unsigned long size) { - return 0; } -void pcibios_align_resource(void *data, struct resource *res, unsigned long size) +int pcibios_enable_device(struct pci_dev *dev) { + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + r = dev->resource + idx; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because" + " of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; } diff -u --recursive --new-file v2.3.42/linux/arch/arm/kernel/time-acorn.c linux/arch/arm/kernel/time-acorn.c --- v2.3.42/linux/arch/arm/kernel/time-acorn.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/time-acorn.c Sun Feb 6 17:45:25 2000 @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/kernel/time-acorn.c + * + * Copyright (c) 1996-2000 Russell King. + * + * Changelog: + * 24-Sep-1996 RMK Created + * 10-Oct-1996 RMK Brought up to date with arch-sa110eval + * 04-Dec-1997 RMK Updated for new arch/arm/time.c + */ +#include +#include +#include + +#include +#include +#include +#include + +extern unsigned long (*gettimeoffset)(void); + +static unsigned long ioctime_gettimeoffset(void) +{ + unsigned int count1, count2, status1, status2; + unsigned long offset = 0; + + status1 = inb(IOC_IRQREQA); + barrier (); + outb (0, IOC_T0LATCH); + barrier (); + count1 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8); + barrier (); + status2 = inb(IOC_IRQREQA); + barrier (); + outb (0, IOC_T0LATCH); + barrier (); + count2 = inb(IOC_T0CNTL) | (inb(IOC_T0CNTH) << 8); + + if (count2 < count1) { + /* + * This means that we haven't just had an interrupt + * while reading into status2. + */ + if (status2 & (1 << 5)) + offset = tick; + count1 = count2; + } else if (count2 > count1) { + /* + * We have just had another interrupt while reading + * status2. + */ + offset += tick; + count1 = count2; + } + + count1 = LATCH - count1; + /* + * count1 = number of clock ticks since last interrupt + */ + offset += count1 * tick / LATCH; + return offset; +} + +void __init ioctime_init(void) +{ + outb(LATCH & 255, IOC_T0LTCHL); + outb(LATCH >> 8, IOC_T0LTCHH); + outb(0, IOC_T0GO); + + gettimeoffset = ioctime_gettimeoffset; +} diff -u --recursive --new-file v2.3.42/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.3.42/linux/arch/arm/kernel/time.c Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/kernel/time.c Tue Feb 8 12:01:59 2000 @@ -12,15 +12,12 @@ * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills */ +#include #include #include #include -#include -#include -#include #include #include -#include #include #include @@ -32,6 +29,7 @@ #include extern int setup_arm_irq(int, struct irqaction *); +extern void setup_timer(void); extern volatile unsigned long lost_ticks; /* change this if you have some constant time drift */ @@ -45,6 +43,26 @@ #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) #endif +static int dummy_set_rtc(void) +{ + return 0; +} + +/* + * hook for setting the RTC's idea of the current time. + */ +int (*set_rtc)(void) = dummy_set_rtc; + +static unsigned long dummy_gettimeoffset(void) +{ + return 0; +} + +/* + * hook for getting the time offset + */ +unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; + /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. @@ -60,9 +78,9 @@ * machines were long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */ -unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) +unsigned long +mktime(unsigned int year, unsigned int mon, unsigned int day, + unsigned int hour, unsigned int min, unsigned int sec) { if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ mon += 12; /* Puts Feb last since it has leap day */ @@ -77,11 +95,14 @@ } /* - * Handle profile stuff... + * Handle kernel profile stuff... */ -static void do_profile(unsigned long pc) +static inline void do_profile(struct pt_regs *regs) { - if (prof_buffer && current->pid) { + if (!user_mode(regs) && + prof_buffer && + current->pid) { + unsigned long pc = instruction_pointer(regs); extern int _stext; pc -= (unsigned long)&_stext; @@ -95,12 +116,61 @@ } } -#include +static long next_rtc_update; + +/* + * If we have an externally synchronized linux clock, then update + * CMOS clock accordingly every ~11 minutes. set_rtc() has to be + * called as close as possible to 500 ms before the new second + * starts. + */ +static inline void do_set_rtc(void) +{ + if (time_status & STA_UNSYNC || set_rtc == NULL) + return; + + if (next_rtc_update && + time_before(xtime.tv_sec, next_rtc_update)) + return; + + if (xtime.tv_usec < 50000 - (tick >> 1) && + xtime.tv_usec >= 50000 + (tick >> 1)) + return; + + if (set_rtc()) + /* + * rtc update failed. Try again in 60s + */ + next_rtc_update = xtime.tv_sec + 60; + else + next_rtc_update = xtime.tv_sec + 660; +} + +#ifdef CONFIG_LEDS -static unsigned long do_gettimeoffset(void) +#include + +static void do_leds(void) { - return gettimeoffset (); + static unsigned int count = 50; + static int last_pid; + + if (current->pid != last_pid) { + last_pid = current->pid; + if (last_pid) + leds_event(led_idle_end); + else + leds_event(led_idle_start); + } + + if (--count == 0) { + count = 50; + leds_event(led_timer); + } } +#else +#define do_leds() +#endif void do_gettimeofday(struct timeval *tv) { @@ -108,7 +178,7 @@ save_flags_cli (flags); *tv = xtime; - tv->tv_usec += do_gettimeoffset(); + tv->tv_usec += gettimeoffset(); /* * xtime is atomically updated in timer_bh. lost_ticks is @@ -134,7 +204,7 @@ * Discover what correction gettimeofday * would have done, and then undo it! */ - tv->tv_usec -= do_gettimeoffset(); + tv->tv_usec -= gettimeoffset(); if (tv->tv_usec < 0) { tv->tv_usec += 1000000; @@ -149,9 +219,25 @@ sti(); } +static struct irqaction timer_irq = { + NULL, 0, 0, "timer", NULL, NULL +}; + +/* + * Include architecture specific code + */ +#include + +/* + * This must cause the timer to start ticking. + * It doesn't have to set the current time though + * from an RTC - it can be done later once we have + * some buses initialised. + */ void __init time_init(void) { xtime.tv_usec = 0; + xtime.tv_sec = 0; setup_timer(); } diff -u --recursive --new-file v2.3.42/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c --- v2.3.42/linux/arch/arm/kernel/traps.c Fri Jan 21 18:19:15 2000 +++ linux/arch/arm/kernel/traps.c Sun Feb 6 17:45:25 2000 @@ -370,7 +370,7 @@ asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs) { - unsigned long phys, addr = instruction_pointer(regs); + unsigned long addr = instruction_pointer(regs); #ifdef CONFIG_DEBUG_ERRORS dump_instr(addr, 1); @@ -383,11 +383,8 @@ pmd_t *pmd; pmd = pmd_offset (pgd, addr); printk (", *pmd = %08lx", pmd_val (*pmd)); - if (!pmd_none (*pmd)) { - unsigned long ptr = pte_page(*pte_offset(pmd, addr)); - printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr))); - phys = ptr + (addr & 0x7fff); - } + if (!pmd_none (*pmd)) + printk (", *pte = %08lx", pte_val(*pte_offset (pmd, addr))); } printk ("\n"); } diff -u --recursive --new-file v2.3.42/linux/arch/arm/lib/io.c linux/arch/arm/lib/io.c --- v2.3.42/linux/arch/arm/lib/io.c Mon Jul 19 09:52:57 1999 +++ linux/arch/arm/lib/io.c Sun Feb 6 17:45:25 2000 @@ -1,4 +1,5 @@ #include +#include #include @@ -6,7 +7,7 @@ * Copy data from IO memory space to "real" memory space. * This needs to be optimized. */ -void _memcpy_fromio(void * to, unsigned long from, unsigned long count) +void _memcpy_fromio(void * to, unsigned long from, size_t count) { while (count) { count--; @@ -20,7 +21,7 @@ * Copy data from "real" memory space to IO memory space. * This needs to be optimized. */ -void _memcpy_toio(unsigned long to, const void * from, unsigned long count) +void _memcpy_toio(unsigned long to, const void * from, size_t count) { while (count) { count--; @@ -34,7 +35,7 @@ * "memset" on IO memory space. * This needs to be optimized. */ -void _memset_io(unsigned long dst, int c, unsigned long count) +void _memset_io(unsigned long dst, int c, size_t count) { while (count) { count--; diff -u --recursive --new-file v2.3.42/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.3.42/linux/arch/arm/mm/init.c Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/mm/init.c Wed Feb 9 20:08:09 2000 @@ -35,8 +35,6 @@ static unsigned long totalram_pages; pgd_t swapper_pg_dir[PTRS_PER_PGD]; -extern void show_net_buffers(void); - /* * empty_bad_page is the page that is used for page faults when * linux is out-of-memory. Older versions of linux just did a @@ -157,9 +155,6 @@ printk("%ld page tables cached\n", pgtable_cache_size); #endif show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } /* diff -u --recursive --new-file v2.3.42/linux/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c --- v2.3.42/linux/arch/arm/mm/ioremap.c Tue Nov 23 22:42:20 1999 +++ linux/arch/arm/mm/ioremap.c Sun Feb 6 17:45:25 2000 @@ -115,7 +115,7 @@ * 'flags' are the extra L_PTE_ flags that you want to specify for this * mapping. See include/asm-arm/proc-armv/pgtable.h for more information. */ -void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) +void * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags) { void * addr; struct vm_struct * area; diff -u --recursive --new-file v2.3.42/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.3.42/linux/arch/arm/mm/mm-armv.c Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/mm/mm-armv.c Sun Feb 6 17:45:25 2000 @@ -34,6 +34,7 @@ { cr_alignment &= ~4; cr_no_alignment &= ~4; + flush_cache_all(); set_cr(cr_alignment); return 1; } @@ -42,6 +43,7 @@ { cr_alignment &= ~(8|4); cr_no_alignment &= ~(8|4); + flush_cache_all(); set_cr(cr_alignment); return 1; } @@ -284,7 +286,7 @@ void __init pagetable_init(void) { - struct map_desc *init_maps, *p; + struct map_desc *init_maps, *p, *q; unsigned long address = 0; int i; @@ -358,17 +360,18 @@ * pgdir entries that are not in the description. */ i = 0; + q = init_maps; do { - if (address < init_maps->virtual || init_maps == p) { + if (address < q->virtual || q == p) { clear_mapping(address); address += PGDIR_SIZE; } else { - create_mapping(init_maps); + create_mapping(q); - address = init_maps->virtual + init_maps->length; + address = q->virtual + q->length; address = (address + PGDIR_SIZE - 1) & PGDIR_MASK; - init_maps ++; + q ++; } } while (address != 0); diff -u --recursive --new-file v2.3.42/linux/arch/i386/boot/compressed/head.S linux/arch/i386/boot/compressed/head.S --- v2.3.42/linux/arch/i386/boot/compressed/head.S Fri Jan 7 19:13:21 2000 +++ linux/arch/i386/boot/compressed/head.S Mon Feb 7 19:59:39 2000 @@ -12,10 +12,6 @@ * the page directory. [According to comments etc elsewhere on a compressed * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] * - * In SMP mode we keep this page safe. Really we ought to shuffle things and - * put the trampoline here. - AC. An SMP trampoline enters with %cx holding - * the stack base. - * * Page 0 is deliberately kept safe, since System Management Mode code in * laptops may need to access the BIOS data stored there. This is also * useful for future device drivers that either access the BIOS via VM86 @@ -41,24 +37,7 @@ movl %ax,%es movl %ax,%fs movl %ax,%gs -#ifdef __SMP__ - orw %bx,%bx # What state are we in BX=1 for SMP - # 0 for boot - jz 2f # Initial boot -/* - * We are trampolining an SMP processor - */ - mov %ax,%ss - xorl %eax,%eax # Back to 0 - mov %cx,%ax # SP low 16 bits - movl %eax,%esp - pushl $0 # Clear NT - popfl - ljmp $(__KERNEL_CS), $0x100000 # Into C and sanity - -2: -#endif lss SYMBOL_NAME(stack_start),%esp xorl %eax,%eax 1: incl %eax # check that A20 really IS enabled diff -u --recursive --new-file v2.3.42/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.42/linux/arch/i386/defconfig Fri Jan 28 15:09:06 2000 +++ linux/arch/i386/defconfig Thu Feb 10 12:44:22 2000 @@ -173,7 +173,9 @@ # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set +CONFIG_ST_EXTRA_DEVS=2 # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -228,6 +230,7 @@ # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set @@ -272,7 +275,7 @@ # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set # CONFIG_DE4X5 is not set -# CONFIG_DEC_ELCP is not set +# CONFIG_TULIP is not set # CONFIG_DGRS is not set CONFIG_EEXPRESS_PRO100=y # CONFIG_NE2K_PCI is not set @@ -429,7 +432,6 @@ # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_BFS_FS_WRITE is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set # CONFIG_UMSDOS_FS is not set diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.3.42/linux/arch/i386/kernel/Makefile Fri Jan 28 15:09:06 2000 +++ linux/arch/i386/kernel/Makefile Thu Feb 10 12:35:19 2000 @@ -40,23 +40,19 @@ endif endif -ifdef CONFIG_ACPI -OX_OBJS += pm.o -else -ifdef CONFIG_APM -OX_OBJS += pm.o -endif -endif - ifeq ($(CONFIG_ACPI),y) - O_OBJS += acpi.o +O_OBJS += acpi.o +else + ifeq ($(CONFIG_ACPI),m) + M_OBJS += acpi.o + endif endif ifeq ($(CONFIG_APM),y) -OX_OBJS += apm.o +O_OBJS += apm.o else ifeq ($(CONFIG_APM),m) - MX_OBJS += apm.o + M_OBJS += apm.o endif endif diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c --- v2.3.42/linux/arch/i386/kernel/acpi.c Fri Jan 28 15:09:06 2000 +++ linux/arch/i386/kernel/acpi.c Tue Feb 8 11:32:18 2000 @@ -105,7 +105,6 @@ static int acpi_p_lvl3_tested = 0; static int acpi_disabled = 0; -int acpi_active = 0; // bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb static unsigned long acpi_slp_typ[] = @@ -564,7 +563,7 @@ /* * Init VIA ACPI device and create a fake FACP */ -static int __init acpi_init_via686a(struct pci_dev *dev) +static int __init acpi_init_via(struct pci_dev *dev) { u32 base; u8 tmp, irq; @@ -631,6 +630,7 @@ { CH_UNKNOWN = 0, CH_INTEL_PIIX4, + CH_VIA_586, CH_VIA_686A, } acpi_chip_t; @@ -642,12 +642,13 @@ { {NULL,}, {acpi_init_piix4}, - {acpi_init_via686a}, + {acpi_init_via}, }; const static struct pci_device_id acpi_pci_tbl[] = { {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4}, + {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586}, {0x1106, 0x3057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_686A}, {0,}, /* terminate list */ }; @@ -792,7 +793,7 @@ /* * Idle loop (uniprocessor only) */ -static void acpi_idle_handler(void) +static void acpi_idle(void) { static int sleep_level = 1; struct acpi_facp *facp = acpi_facp; @@ -1009,56 +1010,63 @@ /* * Enter soft-off (S5) */ -static void acpi_power_off_handler(void) +static void acpi_power_off(void) { acpi_enter_sx(ACPI_S5); } /* + * Claim I/O port if available + */ +static int acpi_claim(unsigned long start, unsigned long size) +{ + if (start && size) { + if (check_region(start, size)) + return -EBUSY; + request_region(start, size, "acpi"); + } + return 0; +} + +/* * Claim ACPI I/O ports */ static int acpi_claim_ioports(struct acpi_facp *facp) { // we don't get a guarantee of contiguity for any of the ACPI registers - if (facp->pm1a_evt) - request_region(facp->pm1a_evt, facp->pm1_evt_len, "acpi"); - if (facp->pm1b_evt) - request_region(facp->pm1b_evt, facp->pm1_evt_len, "acpi"); - if (facp->pm1a_cnt) - request_region(facp->pm1a_cnt, facp->pm1_cnt_len, "acpi"); - if (facp->pm1b_cnt) - request_region(facp->pm1b_cnt, facp->pm1_cnt_len, "acpi"); - if (facp->pm_tmr) - request_region(facp->pm_tmr, facp->pm_tm_len, "acpi"); - if (facp->gpe0) - request_region(facp->gpe0, facp->gpe0_len, "acpi"); - if (facp->gpe1) - request_region(facp->gpe1, facp->gpe1_len, "acpi"); - + if (acpi_claim(facp->pm1a_evt, facp->pm1_evt_len) + || acpi_claim(facp->pm1b_evt, facp->pm1_evt_len) + || acpi_claim(facp->pm1a_cnt, facp->pm1_cnt_len) + || acpi_claim(facp->pm1b_cnt, facp->pm1_cnt_len) + || acpi_claim(facp->pm_tmr, facp->pm_tm_len) + || acpi_claim(facp->gpe0, facp->gpe0_len) + || acpi_claim(facp->gpe1, facp->gpe1_len)) + return -EBUSY; return 0; } /* + * Release I/O port if claimed + */ +static void acpi_release(unsigned long start, unsigned long size) +{ + if (start && size) + release_region(start, size); +} + +/* * Free ACPI I/O ports */ static int acpi_release_ioports(struct acpi_facp *facp) { // we don't get a guarantee of contiguity for any of the ACPI registers - if (facp->pm1a_evt) - release_region(facp->pm1a_evt, facp->pm1_evt_len); - if (facp->pm1b_evt) - release_region(facp->pm1b_evt, facp->pm1_evt_len); - if (facp->pm1a_cnt) - release_region(facp->pm1a_cnt, facp->pm1_cnt_len); - if (facp->pm1b_cnt) - release_region(facp->pm1b_cnt, facp->pm1_cnt_len); - if (facp->pm_tmr) - release_region(facp->pm_tmr, facp->pm_tm_len); - if (facp->gpe0) - release_region(facp->gpe0, facp->gpe0_len); - if (facp->gpe1) - release_region(facp->gpe1, facp->gpe1_len); - + acpi_release(facp->gpe1, facp->gpe1_len); + acpi_release(facp->gpe0, facp->gpe0_len); + acpi_release(facp->pm_tmr, facp->pm_tm_len); + acpi_release(facp->pm1b_cnt, facp->pm1_cnt_len); + acpi_release(facp->pm1a_cnt, facp->pm1_cnt_len); + acpi_release(facp->pm1b_evt, facp->pm1_evt_len); + acpi_release(facp->pm1a_evt, facp->pm1_evt_len); return 0; } @@ -1322,6 +1330,14 @@ = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat * 5); } + if (acpi_claim_ioports(acpi_facp)) { + printk(KERN_ERR "ACPI: I/O port allocation failed\n"); + if (pci_driver_registered) + pci_unregister_driver(&acpi_driver); + acpi_destroy_tables(); + return -ENODEV; + } + if (acpi_facp->sci_int && request_irq(acpi_facp->sci_int, acpi_irq, @@ -1338,16 +1354,15 @@ return -ENODEV; } - acpi_claim_ioports(acpi_facp); acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); pid = kernel_thread(acpi_control_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - acpi_power_off = acpi_power_off_handler; + pm_power_off = acpi_power_off; - acpi_active = 1; + pm_active = 1; /* * Set up the ACPI idle function. Note that we can't really @@ -1360,7 +1375,7 @@ #endif if (acpi_facp->pm_tmr) - acpi_idle = acpi_idle_handler; + pm_idle = acpi_idle; return 0; } @@ -1370,8 +1385,8 @@ */ static void __exit acpi_exit(void) { - acpi_idle = NULL; - acpi_power_off = NULL; + pm_idle = NULL; + pm_power_off = NULL; unregister_sysctl_table(acpi_sysctl); acpi_disable(acpi_facp); diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.3.42/linux/arch/i386/kernel/apm.c Fri Jan 28 15:09:06 2000 +++ linux/arch/i386/kernel/apm.c Tue Feb 8 11:32:18 2000 @@ -150,13 +150,7 @@ #include #include -/* - * Make APM look as much as just another ACPI module as possible.. - */ -#include - -EXPORT_SYMBOL(apm_register_callback); -EXPORT_SYMBOL(apm_unregister_callback); +#include extern unsigned long get_cmos_time(void); extern void machine_real_restart(unsigned char *, int); @@ -304,13 +298,6 @@ #define NR_APM_EVENT_NAME \ (sizeof(apm_event_name) / sizeof(apm_event_name[0])) -typedef struct callback_list_t { - int (* callback)(apm_event_t); - struct callback_list_t * next; -} callback_list_t; - -static callback_list_t * callback_list = NULL; - typedef struct lookup_t { int key; char * msg; @@ -687,32 +674,6 @@ } #endif -int apm_register_callback(int (*callback)(apm_event_t)) -{ - callback_list_t * new; - - new = kmalloc(sizeof(callback_list_t), GFP_KERNEL); - if (new == NULL) - return -ENOMEM; - new->callback = callback; - new->next = callback_list; - callback_list = new; - return 0; -} - -void apm_unregister_callback(int (*callback)(apm_event_t)) -{ - callback_list_t ** ptr; - callback_list_t * old; - - for (ptr = &callback_list; *ptr != NULL; ptr = &(*ptr)->next) - if ((*ptr)->callback == callback) - break; - old = *ptr; - *ptr = old->next; - kfree_s(old, sizeof(callback_list_t)); -} - static int queue_empty(struct apm_bios_struct * as) { return as->event_head == as->event_tail; @@ -848,17 +809,26 @@ static int send_event(apm_event_t event, apm_event_t undo, struct apm_bios_struct *sender) { - callback_list_t * call; - callback_list_t * fix; - - for (call = callback_list; call != NULL; call = call->next) { - if (call->callback(event) && undo) { - for (fix = callback_list; fix != call; fix = fix->next) - fix->callback(undo); + switch (event) { + case APM_SYS_SUSPEND: + case APM_CRITICAL_SUSPEND: + case APM_USER_SUSPEND: + /* map all suspends to ACPI D3 */ + if (pm_send_request(PM_SUSPEND, (void*) 3)) { + if (apm_bios_info.version > 0x100) + apm_set_power_state(APM_STATE_REJECT); + return 0; + } + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + /* map all resumes to ACPI D0 */ + if (pm_send_request(PM_RESUME, 0)) { if (apm_bios_info.version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; } + break; } queue_event(event, sender); @@ -1373,7 +1343,7 @@ /* Install our power off handler.. */ if (power_off_enabled) - acpi_power_off = apm_power_off; + pm_power_off = apm_power_off; #ifdef CONFIG_MAGIC_SYSRQ sysrq_power_off = apm_power_off; #endif @@ -1381,6 +1351,8 @@ console_blank_hook = apm_console_blank; #endif + pm_active = 1; + apm_mainloop(); return 0; } @@ -1484,12 +1456,10 @@ APM_INIT_ERROR_RETURN; } -#ifdef CONFIG_ACPI - if (acpi_active) { + if (PM_IS_ACTIVE()) { printk(KERN_NOTICE "apm: overridden by ACPI.\n"); APM_INIT_ERROR_RETURN; } -#endif /* * Set up a segment that references the real mode segment 0x40 @@ -1551,4 +1521,4 @@ return 0; } -module_init(apm_init) +__initcall(apm_init); diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.3.42/linux/arch/i386/kernel/entry.S Fri Jan 28 15:09:06 2000 +++ linux/arch/i386/kernel/entry.S Wed Feb 9 20:08:09 2000 @@ -76,6 +76,7 @@ addr_limit = 12 exec_domain = 16 need_resched = 20 +processor = 56 ENOSYS = 38 @@ -203,9 +204,17 @@ .globl ret_from_sys_call .globl ret_from_intr ret_from_sys_call: - movl SYMBOL_NAME(bh_mask),%eax - andl SYMBOL_NAME(bh_active),%eax - jne handle_bottom_half +#ifdef __SMP__ + movl processor(%ebx),%eax + shll $5,%eax + movl SYMBOL_NAME(softirq_state)(,%eax),%ecx + testl SYMBOL_NAME(softirq_state)+4(,%eax),%ecx +#else + movl SYMBOL_NAME(softirq_state),%ecx + testl SYMBOL_NAME(softirq_state)+4,%ecx +#endif + jne handle_softirq + ret_with_reschedule: cmpl $0,need_resched(%ebx) jne reschedule @@ -250,9 +259,18 @@ ALIGN ret_from_exception: - movl SYMBOL_NAME(bh_mask),%eax - andl SYMBOL_NAME(bh_active),%eax - jne handle_bottom_half +#ifdef __SMP__ + GET_CURRENT(%ebx) + movl processor(%ebx),%eax + shll $5,%eax + movl SYMBOL_NAME(softirq_state)(,%eax),%ecx + testl SYMBOL_NAME(softirq_state)+4(,%eax),%ecx +#else + movl SYMBOL_NAME(softirq_state),%ecx + testl SYMBOL_NAME(softirq_state)+4,%ecx +#endif + jne handle_softirq + ALIGN ret_from_intr: GET_CURRENT(%ebx) @@ -263,10 +281,10 @@ jmp restore_all ALIGN -handle_bottom_half: - call SYMBOL_NAME(do_bottom_half) +handle_softirq: + call SYMBOL_NAME(do_softirq) jmp ret_from_intr - + ALIGN reschedule: call SYMBOL_NAME(schedule) # test diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.3.42/linux/arch/i386/kernel/head.S Fri Jan 7 19:13:21 2000 +++ linux/arch/i386/kernel/head.S Mon Feb 7 19:59:39 2000 @@ -212,17 +212,6 @@ orl $2,%eax # set MP 2: movl %eax,%cr0 call check_x87 -#ifdef __SMP__ - movb ready,%al # First CPU if 0 - orb %al,%al - jz 4f # First CPU skip this stuff - movl %cr4,%eax # Turn on 4Mb pages - orl $16,%eax - movl %eax,%cr4 - movl %cr3,%eax # Intel specification clarification says - movl %eax,%cr3 # to do this. Maybe it makes a difference. - # Who knows ? -#endif 4: #ifdef __SMP__ incb ready diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.3.42/linux/arch/i386/kernel/i386_ksyms.c Fri Jan 28 15:09:06 2000 +++ linux/arch/i386/kernel/i386_ksyms.c Wed Feb 9 20:08:09 2000 @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -44,14 +44,13 @@ EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(__io_virt_debug); -EXPORT_SYMBOL(local_bh_count); -EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); +EXPORT_SYMBOL(probe_irq_mask); EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(acpi_idle); -EXPORT_SYMBOL(acpi_power_off); +EXPORT_SYMBOL(pm_idle); +EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); @@ -106,11 +105,7 @@ /* Global SMP irq stuff */ EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(synchronize_bh); -EXPORT_SYMBOL(global_bh_count); -EXPORT_SYMBOL(global_bh_lock); EXPORT_SYMBOL(global_irq_holder); -EXPORT_SYMBOL(i386_bh_lock); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); @@ -141,3 +136,7 @@ #endif EXPORT_SYMBOL(get_wchan); + + +EXPORT_SYMBOL(local_bh_count); +EXPORT_SYMBOL(local_irq_count); diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.3.42/linux/arch/i386/kernel/io_apic.c Fri Jan 21 18:19:16 2000 +++ linux/arch/i386/kernel/io_apic.c Tue Feb 8 09:37:35 2000 @@ -223,7 +223,7 @@ static int __init pin_2_irq(int idx, int apic, int pin); int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin) { - int apic, i; + int apic, i, best_guess = -1; for (i = 0; i < mp_irq_entries; i++) { int lbus = mp_irqs[i].mpc_srcbus; @@ -236,10 +236,18 @@ (mp_bus_id_to_type[lbus] == MP_BUS_PCI) && !mp_irqs[i].mpc_irqtype && (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) && - (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) && - (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))) + (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { + int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); - return pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); + if (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3)) + return irq; + /* + * Use the first all-but-pin matching entry as a + * best-guess fuzzy result for broken mptables. + */ + if (best_guess < 0) + best_guess = irq; + } } return -1; } diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.42/linux/arch/i386/kernel/irq.c Fri Jan 21 18:19:16 2000 +++ linux/arch/i386/kernel/irq.c Wed Feb 9 20:08:09 2000 @@ -182,30 +182,12 @@ * Global interrupt locks for SMP. Allow interrupts to come in on any * CPU, yet make cli/sti act globally to protect critical regions.. */ -spinlock_t i386_bh_lock = SPIN_LOCK_UNLOCKED; #ifdef CONFIG_SMP unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; atomic_t global_irq_count; -atomic_t global_bh_count; -atomic_t global_bh_lock; - -/* - * "global_cli()" is a special case, in that it can hold the - * interrupts disabled for a longish time, and also because - * we may be doing TLB invalidates when holding the global - * IRQ lock for historical reasons. Thus we may need to check - * SMP invalidate events specially by hand here (but not in - * any normal spinlocks) - */ -static inline void check_smp_invalidate(int cpu) -{ - if (test_bit(cpu, &smp_invalidate_needed)) - do_flush_tlb_local(); -} - static void show(char * str) { int i; @@ -216,7 +198,7 @@ printk("irq: %d [%d %d]\n", atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); printk("bh: %d [%d %d]\n", - atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]); + spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count[0], local_bh_count[1]); stack = (unsigned long *) &stack; for (i = 40; i ; i--) { unsigned long x = *++stack; @@ -228,18 +210,6 @@ #define MAXCOUNT 100000000 -static inline void wait_on_bh(void) -{ - int count = MAXCOUNT; - do { - if (!--count) { - show("wait_on_bh"); - count = ~0; - } - /* nothing .. wait for the other bh's to go away */ - } while (atomic_read(&global_bh_count) != 0); -} - /* * I had a lockup scenario where a tight loop doing * spin_unlock()/spin_lock() on CPU#1 was racing with @@ -279,7 +249,7 @@ * already executing in one.. */ if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + if (local_bh_count[cpu] || !spin_is_locked(&global_bh_lock)) break; } @@ -294,12 +264,11 @@ __sti(); SYNC_OTHER_CORES(cpu); __cli(); - check_smp_invalidate(cpu); if (atomic_read(&global_irq_count)) continue; if (global_irq_lock) continue; - if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + if (!local_bh_count[cpu] && spin_is_locked(&global_bh_lock)) continue; if (!test_and_set_bit(0,&global_irq_lock)) break; @@ -309,20 +278,6 @@ /* * This is called when we want to synchronize with - * bottom half handlers. We need to wait until - * no other CPU is executing any bottom half handler. - * - * Don't wait if we're already running in an interrupt - * context or are inside a bh handler. - */ -void synchronize_bh(void) -{ - if (atomic_read(&global_bh_count) && !in_interrupt()) - wait_on_bh(); -} - -/* - * This is called when we want to synchronize with * interrupts. We may for example tell a device to * stop sending interrupts: but to make sure there * are no interrupts that are executing on another @@ -346,7 +301,6 @@ /* Uhhuh.. Somebody else got it. Wait.. */ do { do { - check_smp_invalidate(cpu); } while (test_bit(0,&global_irq_lock)); } while (test_and_set_bit(0,&global_irq_lock)); } @@ -621,16 +575,8 @@ desc->handler->end(irq); spin_unlock(&irq_controller_lock); - /* - * This should be conditional: we should really get - * a return code from the irq handler to tell us - * whether the handler wants us to do software bottom - * half handling or not.. - */ - if (1) { - if (bh_active & bh_mask) - do_bottom_half(); - } + if (softirq_state[cpu].active&softirq_state[cpu].mask) + do_softirq(); return 1; } diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.3.42/linux/arch/i386/kernel/mtrr.c Fri Jan 7 19:13:21 2000 +++ linux/arch/i386/kernel/mtrr.c Wed Feb 9 11:42:35 2000 @@ -1469,19 +1469,10 @@ static struct file_operations mtrr_fops = { - NULL, /* Seek */ - mtrr_read, /* Read */ - mtrr_write, /* Write */ - NULL, /* Readdir */ - NULL, /* Poll */ - mtrr_ioctl, /* IOctl */ - NULL, /* MMAP */ - NULL, /* Open */ - NULL, /* Flush */ - mtrr_close, /* Release */ - NULL, /* Fsync */ - NULL, /* Fasync */ - NULL, /* Lock */ + read: mtrr_read, + write: mtrr_write, + ioctl: mtrr_ioctl, + release: mtrr_close, }; static struct inode_operations proc_mtrr_inode_operations = { diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.3.42/linux/arch/i386/kernel/pci-pc.c Fri Jan 21 18:19:16 2000 +++ linux/arch/i386/kernel/pci-pc.c Thu Feb 10 12:30:30 2000 @@ -939,12 +939,26 @@ } } +static void __init pci_fixup_ide_trash(struct pci_dev *d) +{ + int i; + + /* + * There exist PCI IDE controllers which have utter garbage + * in first four base registers. Ignore that. + */ + DBG("PCI: IDE base address trash cleared for %s\n", d->slot_name); + for(i=0; i<4; i++) + d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_HE, pci_fixup_rcc }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_RCC, PCI_DEVICE_ID_RCC_LE, pci_fixup_rcc }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_6010, pci_fixup_compaq }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash }, { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, { 0 } }; @@ -1132,6 +1146,10 @@ if (pin) { pin--; /* interrupt pins are numbered starting from 1 */ irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); +/* + * Will be removed completely if things work out well with fuzzy parsing + */ +#if 0 if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ struct pci_dev * bridge = dev->bus->self; @@ -1142,6 +1160,7 @@ printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq); } +#endif if (irq >= 0) { printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/pm.c linux/arch/i386/kernel/pm.c --- v2.3.42/linux/arch/i386/kernel/pm.c Fri Jan 28 15:09:06 2000 +++ linux/arch/i386/kernel/pm.c Wed Dec 31 16:00:00 1969 @@ -1,104 +0,0 @@ -/* - * pm.c - Power management interface - * - * Copyright (C) 2000 Andrew Henroid - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -static spinlock_t pm_devs_lock = SPIN_LOCK_UNLOCKED; -static LIST_HEAD(pm_devs); - -/* - * Register a device with power management - */ -struct pm_dev *pm_register(pm_dev_t type, - unsigned long id, - pm_callback callback) -{ - struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); - if (dev) { - unsigned long flags; - - memset(dev, 0, sizeof(*dev)); - dev->type = type; - dev->id = id; - dev->callback = callback; - - spin_lock_irqsave(&pm_devs_lock, flags); - list_add(&dev->entry, &pm_devs); - spin_unlock_irqrestore(&pm_devs_lock, flags); - } - return dev; -} - -/* - * Unregister a device with power management - */ -void pm_unregister(struct pm_dev *dev) -{ - if (dev) { - unsigned long flags; - - spin_lock_irqsave(&pm_devs_lock, flags); - list_del(&dev->entry); - spin_unlock_irqrestore(&pm_devs_lock, flags); - - kfree(dev); - } -} - -/* - * Send a request to all devices - */ -int pm_send_request(pm_request_t rqst, void *data) -{ - struct list_head *entry = pm_devs.next; - while (entry != &pm_devs) { - struct pm_dev *dev = list_entry(entry, struct pm_dev, entry); - if (dev->callback) { - int status = (*dev->callback)(dev, rqst, data); - if (status) - return status; - } - entry = entry->next; - } - return 0; -} - -/* - * Find a device - */ -struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from) -{ - struct list_head *entry = from ? from->entry.next:pm_devs.next; - while (entry != &pm_devs) { - struct pm_dev *dev = list_entry(entry, struct pm_dev, entry); - if (type == PM_UNKNOWN_DEV || dev->type == type) - return dev; - entry = entry->next; - } - return 0; -} - -EXPORT_SYMBOL(pm_register); -EXPORT_SYMBOL(pm_unregister); -EXPORT_SYMBOL(pm_send_request); -EXPORT_SYMBOL(pm_find); diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.3.42/linux/arch/i386/kernel/process.c Mon Dec 20 18:48:21 1999 +++ linux/arch/i386/kernel/process.c Tue Feb 8 11:32:18 2000 @@ -61,12 +61,12 @@ /* * Powermanagement idle function, if any.. */ -void (*acpi_idle)(void) = NULL; +void (*pm_idle)(void) = NULL; /* * Power off function, if any */ -void (*acpi_power_off)(void) = NULL; +void (*pm_power_off)(void) = NULL; /* * We use this if we don't have any better @@ -92,7 +92,7 @@ current->counter = -100; while (1) { - void (*idle)(void) = acpi_idle; + void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; while (!current->need_resched) @@ -328,8 +328,8 @@ void machine_power_off(void) { - if (acpi_power_off) - acpi_power_off(); + if (pm_power_off) + pm_power_off(); } diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.42/linux/arch/i386/kernel/setup.c Fri Jan 21 18:19:16 2000 +++ linux/arch/i386/kernel/setup.c Mon Feb 7 20:01:14 2000 @@ -75,7 +75,7 @@ #include #include #include - +#include /* * Machine setup.. */ @@ -1543,6 +1543,10 @@ */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; + if(current->mm) + BUG(); + enter_lazy_tlb(&init_mm, current, nr); + t->esp0 = current->thread.esp0; set_tss_desc(nr,t); gdt_table[__TSS(nr)].b &= 0xfffffdff; diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.3.42/linux/arch/i386/kernel/smp.c Fri Jan 21 18:19:16 2000 +++ linux/arch/i386/kernel/smp.c Tue Feb 8 18:44:57 2000 @@ -103,8 +103,7 @@ /* The 'big kernel lock' */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; -volatile unsigned long smp_invalidate_needed; /* immediate flush required */ -unsigned int cpu_tlbbad[NR_CPUS]; /* flush before returning to user space */ +struct tlb_state cpu_tlbstate[NR_CPUS]; /* * the following functions deal with sending IPIs between CPUs. @@ -186,15 +185,15 @@ return cfg; } -static inline int __prepare_ICR2 (unsigned int dest) +static inline int __prepare_ICR2 (unsigned int mask) { unsigned int cfg; cfg = __get_ICR2(); #if LOGICAL_DELIVERY - cfg |= SET_APIC_DEST_FIELD((1< */ -static void flush_tlb_others(unsigned int cpumask) + +static volatile unsigned long flush_cpumask; +static struct mm_struct * flush_mm; +static unsigned long flush_va; +static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED; +#define FLUSH_ALL 0xffffffff + +static void inline leave_mm (unsigned long cpu) { - int cpu = smp_processor_id(); - int stuck; - unsigned long flags; + if (cpu_tlbstate[cpu].state == TLBSTATE_OK) + BUG(); + clear_bit(cpu, &cpu_tlbstate[cpu].active_mm->cpu_vm_mask); + cpu_tlbstate[cpu].state = TLBSTATE_OLD; +} + +/* + * + * The flush IPI assumes that a thread switch happens in this order: + * 1) set_bit(cpu, &new_mm->cpu_vm_mask); + * 2) update cpu_tlbstate + * [now the cpu can accept tlb flush request for the new mm] + * 3) change cr3 (if required, or flush local tlb,...) + * 4) clear_bit(cpu, &old_mm->cpu_vm_mask); + * 5) switch %%esp, ie current + * + * The interrupt must handle 2 special cases: + * - cr3 is changed before %%esp, ie. it cannot use current->{active_,}mm. + * - the cpu performs speculative tlb reads, i.e. even if the cpu only + * runs in kernel space, the cpu could load tlb entries for user space + * pages. + * + * The good news is that cpu_tlbstate is local to each cpu, no + * write/read ordering problems. + */ + +/* + * TLB flush IPI: + * + * 1) Flush the tlb entries if the cpu uses the mm that's being flushed. + * 2) Leave the mm if we are in the lazy tlb mode. + * We cannot call mmdrop() because we are in interrupt context, + * instead update cpu_tlbstate. + */ + +asmlinkage void smp_invalidate_interrupt (void) +{ + unsigned long cpu = smp_processor_id(); + + if (!test_bit(cpu, &flush_cpumask)) + BUG(); + if (flush_mm == cpu_tlbstate[cpu].active_mm) { + if (cpu_tlbstate[cpu].state == TLBSTATE_OK) { + if (flush_va == FLUSH_ALL) + local_flush_tlb(); + else + __flush_tlb_one(flush_va); + } else + leave_mm(cpu); + } else { + extern void show_stack (void *); + printk("hm #1: %p, %p.\n", flush_mm, cpu_tlbstate[cpu].active_mm); + show_stack(NULL); + } + __flush_tlb(); + ack_APIC_irq(); + clear_bit(cpu, &flush_cpumask); +} + +static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, + unsigned long va) +{ + /* + * A couple of (to be removed) sanity checks: + * + * - we do not send IPIs to not-yet booted CPUs. + * - current CPU must not be in mask + * - mask must exist :) + */ + if (!cpumask) + BUG(); + if ((cpumask & cpu_online_map) != cpumask) + BUG(); + if (cpumask & (1 << smp_processor_id())) + BUG(); + if (!mm) + BUG(); /* - * it's important that we do not generate any APIC traffic - * until the AP CPUs have booted up! + * i'm not happy about this global shared spinlock in the + * MM hot path, but we'll see how contended it is. + * Temporarily this turns IRQs off, so that lockups are + * detected by the NMI watchdog. */ - cpumask &= cpu_online_map; - if (cpumask) { - atomic_set_mask(cpumask, &smp_invalidate_needed); - - /* - * Processors spinning on some lock with IRQs disabled - * will see this IRQ late. The smp_invalidate_needed - * map will ensure they don't do a spurious flush tlb - * or miss one. - */ + spin_lock_irq(&tlbstate_lock); - __save_flags(flags); - __cli(); + flush_mm = mm; + flush_va = va; + atomic_set_mask(cpumask, &flush_cpumask); + /* + * We have to send the IPI only to + * CPUs affected. + */ + send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR); - send_IPI_allbutself(INVALIDATE_TLB_VECTOR); + while (flush_cpumask) + /* nothing. lockup detection does not belong here */; - /* - * Spin waiting for completion - */ - - stuck = 50000000; - while (smp_invalidate_needed) { - /* - * Take care of "crossing" invalidates - */ - if (test_bit(cpu, &smp_invalidate_needed)) - do_flush_tlb_local(); - - --stuck; - if (!stuck) { - printk("stuck on TLB IPI wait (CPU#%d)\n",cpu); - break; - } - } - __restore_flags(flags); - } + flush_mm = NULL; + flush_va = 0; + spin_unlock_irq(&tlbstate_lock); } - -/* - * Smarter SMP flushing macros. - * c/o Linus Torvalds. - * - * These mean you can really definitely utterly forget about - * writing to user space from interrupts. (Its not allowed anyway). - */ + void flush_tlb_current_task(void) { - unsigned long vm_mask = 1 << smp_processor_id(); struct mm_struct *mm = current->mm; - unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; + unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id()); - mm->cpu_vm_mask = vm_mask; - flush_tlb_others(cpu_mask); local_flush_tlb(); + if (cpu_mask) + flush_tlb_others(cpu_mask, mm, FLUSH_ALL); } -void flush_tlb_mm(struct mm_struct * mm) +void flush_tlb_mm (struct mm_struct * mm) { - unsigned long vm_mask = 1 << smp_processor_id(); - unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; + unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id()); - mm->cpu_vm_mask = 0; if (current->active_mm == mm) { - mm->cpu_vm_mask = vm_mask; - local_flush_tlb(); + if (current->mm) + local_flush_tlb(); + else + leave_mm(smp_processor_id()); } - flush_tlb_others(cpu_mask); + if (cpu_mask) + flush_tlb_others(cpu_mask, mm, FLUSH_ALL); } void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) { - unsigned long vm_mask = 1 << smp_processor_id(); struct mm_struct *mm = vma->vm_mm; - unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; + unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id()); - mm->cpu_vm_mask = 0; if (current->active_mm == mm) { - __flush_tlb_one(va); - mm->cpu_vm_mask = vm_mask; + if(current->mm) + __flush_tlb_one(va); + else + leave_mm(smp_processor_id()); } - flush_tlb_others(cpu_mask); + + if (cpu_mask) + flush_tlb_others(cpu_mask, mm, va); } static inline void do_flush_tlb_all_local(void) { - __flush_tlb_all(); - if (!current->mm && current->active_mm) { - unsigned long cpu = smp_processor_id(); + unsigned long cpu = smp_processor_id(); - clear_bit(cpu, ¤t->active_mm->cpu_vm_mask); - cpu_tlbbad[cpu] = 1; - } + __flush_tlb_all(); + if (cpu_tlbstate[cpu].state == TLBSTATE_LAZY) + leave_mm(cpu); } static void flush_tlb_all_ipi(void* info) @@ -410,7 +470,7 @@ void smp_send_reschedule(int cpu) { - send_IPI_single(cpu, RESCHEDULE_VECTOR); + send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR); } /* @@ -512,23 +572,6 @@ asmlinkage void smp_reschedule_interrupt(void) { ack_APIC_irq(); -} - -/* - * Invalidate call-back. - * - * Mark the CPU as a VM user if there is a active - * thread holding on to an mm at this time. This - * allows us to optimize CPU cross-calls even in the - * presense of lazy TLB handling. - */ -asmlinkage void smp_invalidate_interrupt(void) -{ - if (test_bit(smp_processor_id(), &smp_invalidate_needed)) - do_flush_tlb_local(); - - ack_APIC_irq(); - } asmlinkage void smp_call_function_interrupt(void) diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/trampoline.S linux/arch/i386/kernel/trampoline.S --- v2.3.42/linux/arch/i386/kernel/trampoline.S Wed May 6 11:42:54 1998 +++ linux/arch/i386/kernel/trampoline.S Mon Feb 7 19:59:39 2000 @@ -55,7 +55,7 @@ jmp flush_instr flush_instr: ljmpl $__KERNEL_CS, $0x00100000 - # jump to startup_32 + # jump to startup_32 in arch/i386/kernel/head.S idt_48: .word 0 # idt limit = 0 diff -u --recursive --new-file v2.3.42/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.3.42/linux/arch/i386/kernel/traps.c Fri Jan 21 18:19:16 2000 +++ linux/arch/i386/kernel/traps.c Wed Feb 9 19:36:08 2000 @@ -124,19 +124,63 @@ /* * These constants are for searching for possible module text - * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is - * a guess of how much space is likely to be vmalloced. + * segments. MODULE_RANGE is a guess of how much space is likely + * to be vmalloced. */ -#define VMALLOC_OFFSET (8*1024*1024) #define MODULE_RANGE (8*1024*1024) +void show_stack(unsigned long * esp) +{ + unsigned long *stack, addr, module_start, module_end; + int i; + + // debugging aid: "show_stack(NULL);" prints the + // back trace for this cpu. + + if(esp==NULL) + esp=(unsigned long*)&esp; + + stack = esp; + for(i=0; i < kstack_depth_to_print; i++) { + if (((long) stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + + printk("\nCall Trace: "); + stack = esp; + i = 1; + module_start = VMALLOC_START; + module_end = VMALLOC_END; + while (((long) stack & (THREAD_SIZE-1)) != 0) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_stext) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } +} + static void show_registers(struct pt_regs *regs) { int i; int in_kernel = 1; unsigned long esp; unsigned short ss; - unsigned long *stack, addr, module_start, module_end; esp = (unsigned long) (®s->esp); ss = __KERNEL_DS; @@ -160,43 +204,24 @@ * time of the fault.. */ if (in_kernel) { + printk("\nStack: "); - stack = (unsigned long *) esp; - for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) + show_stack((unsigned long*)esp); + + printk("\nCode: "); + if(regs->eip < PAGE_OFFSET) + goto bad; + + for(i=0;i<20;i++) + { + unsigned char c; + if(__get_user(c, &((unsigned char*)regs->eip)[i])) { +bad: + printk(" Bad EIP value."); break; - if (i && ((i % 8) == 0)) - printk("\n "); - printk("%08lx ", *stack++); - } - printk("\nCall Trace: "); - stack = (unsigned long *) esp; - i = 1; - module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); - module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); - module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { - addr = *stack++; - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ - if (((addr >= (unsigned long) &_stext) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { - if (i && ((i % 8) == 0)) - printk("\n "); - printk("[<%08lx>] ", addr); - i++; } + printk("%02x ", c); } - printk("\nCode: "); - for(i=0;i<20;i++) - printk("%02x ", ((unsigned char *)regs->eip)[i]); } printk("\n"); } diff -u --recursive --new-file v2.3.42/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.3.42/linux/arch/i386/mm/init.c Fri Jan 28 15:09:07 2000 +++ linux/arch/i386/mm/init.c Wed Feb 9 20:08:09 2000 @@ -40,8 +40,6 @@ static unsigned long totalram_pages = 0; static unsigned long totalhigh_pages = 0; -extern void show_net_buffers(void); - /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a @@ -228,9 +226,6 @@ printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } /* References to section boundaries */ @@ -448,7 +443,7 @@ kmap_init(); #endif { - unsigned int zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; unsigned int max_dma, high, low; max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; diff -u --recursive --new-file v2.3.42/linux/arch/ia64/Makefile linux/arch/ia64/Makefile --- v2.3.42/linux/arch/ia64/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,125 @@ +# +# ia64/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1998, 1999 by David Mosberger-Tang +# + +NM := $(CROSS_COMPILE)nm -B + +LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds +# next line is for HP compiler backend: +#AFLAGS += -DGCC_RETVAL_POINTER_IN_R8 +# The next line is needed when compiling with the July snapshot of the Cygnus compiler: +#EXTRA = -ma0-bugs -D__GCC_DOESNT_KNOW_IN_REGS__ +# next two lines are for the September snapshot of the Cygnus compiler: +AFLAGS += -D__GCC_MULTIREG_RETVALS__ +EXTRA = -ma0-bugs -D__GCC_MULTIREG_RETVALS__ + +CFLAGS := -g $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 + +ifdef CONFIG_IA64_GENERIC + CORE_FILES := arch/$(ARCH)/hp/hp.a \ + arch/$(ARCH)/sn/sn.a \ + arch/$(ARCH)/dig/dig.a \ + $(CORE_FILES) + SUBDIRS := arch/$(ARCH)/hp \ + arch/$(ARCH)/sn/sn1 \ + arch/$(ARCH)/sn \ + arch/$(ARCH)/dig \ + $(SUBDIRS) + +else # !GENERIC + +ifeq ($(CONFIG_IA64_HP_SIM),y) + SUBDIRS := arch/$(ARCH)/hp \ + $(SUBDIRS) + CORE_FILES := arch/$(ARCH)/hp/hp.a \ + $(CORE_FILES) +endif + +ifeq ($(CONFIG_IA64_SGI_SN1_SIM),y) + SUBDIRS := arch/$(ARCH)/sn/sn1 \ + arch/$(ARCH)/sn \ + $(SUBDIRS) + CORE_FILES := arch/$(ARCH)/sn/sn.a \ + $(CORE_FILES) +endif + +ifeq ($(CONFIG_IA64_SOFTSDV),y) + SUBDIRS := arch/$(ARCH)/dig \ + $(SUBDIRS) + CORE_FILES := arch/$(ARCH)/dig/dig.a \ + $(CORE_FILES) +endif + +ifeq ($(CONFIG_IA64_DIG),y) + SUBDIRS := arch/$(ARCH)/dig \ + $(SUBDIRS) + CORE_FILES := arch/$(ARCH)/dig/dig.a \ + $(CORE_FILES) +endif + +endif # !GENERIC + +ifeq ($(CONFIG_IA32_SUPPORT),y) + SUBDIRS := arch/$(ARCH)/ia32 $(SUBDIRS) + CORE_FILES := arch/$(ARCH)/ia32/ia32.o $(CORE_FILES) +endif + +ifdef CONFIG_KDB + LIBS := $(LIBS) $(TOPDIR)/arch/$(ARCH)/kdb/kdb.a + SUBDIRS := $(SUBDIRS) arch/$(ARCH)/kdb +endif + +HEAD := arch/$(ARCH)/kernel/head.o arch/ia64/kernel/init_task.o + +SUBDIRS := arch/$(ARCH)/tools arch/$(ARCH)/kernel arch/$(ARCH)/mm arch/$(ARCH)/lib $(SUBDIRS) +CORE_FILES := arch/$(ARCH)/kernel/kernel.o arch/$(ARCH)/mm/mm.o $(CORE_FILES) + +LIBS := $(TOPDIR)/arch/$(ARCH)/lib/lib.a $(LIBS) \ + $(TOPDIR)/arch/$(ARCH)/lib/lib.a + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +vmlinux: arch/$(ARCH)/vmlinux.lds + +arch/$(ARCH)/vmlinux.lds: arch/$(ARCH)/vmlinux.lds.S FORCE + gcc -D__ASSEMBLY__ -E -C -P -I$(HPATH) -I$(HPATH)/asm-$(ARCH) \ + arch/$(ARCH)/vmlinux.lds.S > $@ + +FORCE: ; + +rawboot: + @$(MAKEBOOT) rawboot + +# +# My boot writes directly to a specific disk partition, I doubt most +# people will want to do that without changes.. +# +msb my-special-boot: + @$(MAKEBOOT) msb + +bootimage: + @$(MAKEBOOT) bootimage + +srmboot: + @$(MAKEBOOT) srmboot + +archclean: + @$(MAKE) -C arch/$(ARCH)/kernel clean + @$(MAKE) -C arch/$(ARCH)/tools clean + @$(MAKEBOOT) clean + +archmrproper: + rm -f arch/$(ARCH)/vmlinux.lds + @$(MAKE) -C arch/$(ARCH)/tools mrproper + +archdep: + @$(MAKEBOOT) dep + +bootpfile: + @$(MAKEBOOT) bootpfile diff -u --recursive --new-file v2.3.42/linux/arch/ia64/boot/Makefile linux/arch/ia64/boot/Makefile --- v2.3.42/linux/arch/ia64/boot/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/boot/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,33 @@ +# +# ia64/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1998 by David Mosberger-Tang +# + +LINKFLAGS = -static -T bootloader.lds + +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< + +OBJECTS = bootloader.o +TARGETS = + +ifdef CONFIG_IA64_HP_SIM + TARGETS += bootloader +endif + +all: $(TARGETS) + +bootloader: $(OBJECTS) + $(LD) $(LINKFLAGS) $(OBJECTS) $(LIBS) -o bootloader + +clean: + rm -f $(TARGETS) + +dep: diff -u --recursive --new-file v2.3.42/linux/arch/ia64/boot/bootloader.c linux/arch/ia64/boot/bootloader.c --- v2.3.42/linux/arch/ia64/boot/bootloader.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/boot/bootloader.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,234 @@ +/* + * arch/ia64/boot/bootloader.c + * + * Loads an ELF kernel. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999 Stephane Eranian + * + * 01/07/99 S.Eranian modified to pass command line arguments to kernel + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Simulator system calls: */ + +#define SSC_CONSOLE_INIT 20 +#define SSC_GETCHAR 21 +#define SSC_PUTCHAR 31 +#define SSC_OPEN 50 +#define SSC_CLOSE 51 +#define SSC_READ 52 +#define SSC_WRITE 53 +#define SSC_GET_COMPLETION 54 +#define SSC_WAIT_COMPLETION 55 +#define SSC_CONNECT_INTERRUPT 58 +#define SSC_GENERATE_INTERRUPT 59 +#define SSC_SET_PERIODIC_INTERRUPT 60 +#define SSC_GET_RTC 65 +#define SSC_EXIT 66 +#define SSC_LOAD_SYMBOLS 69 +#define SSC_GET_TOD 74 + +#define SSC_GET_ARGS 75 + +struct disk_req { + unsigned long addr; + unsigned len; +}; + +struct disk_stat { + int fd; + unsigned count; +}; + +#include "../kernel/fw-emu.c" + +static void +cons_write (const char *buf) +{ + unsigned long ch; + + while ((ch = *buf++) != '\0') { + ssc(ch, 0, 0, 0, SSC_PUTCHAR); + if (ch == '\n') + ssc('\r', 0, 0, 0, SSC_PUTCHAR); + } +} + +void +enter_virtual_mode (unsigned long new_psr) +{ + asm volatile ("mov cr.ipsr=%0" :: "r"(new_psr)); + asm volatile ("mov cr.iip=%0" :: "r"(&&target)); + asm volatile ("mov cr.ifs=r0"); + asm volatile ("rfi;;"); /* must be last insn in an insn group */ + + target: +} + + +#define MAX_ARGS 32 + +void +_start (void) +{ + register long sp asm ("sp"); + static char stack[16384] __attribute__ ((aligned (16))); + static char mem[4096]; + static char buffer[1024]; + unsigned long flags, off; + int fd, i; + struct disk_req req; + struct disk_stat stat; + struct elfhdr *elf; + struct elf_phdr *elf_phdr; /* program header */ + unsigned long e_entry, e_phoff, e_phnum; + char *kpath, *args; + long arglen = 0; + + asm volatile ("movl gp=__gp" ::: "memory"); + asm volatile ("mov sp=%0" :: "r"(stack) : "memory"); + asm volatile ("bsw.1;;"); +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + asm volative ("nop 0;; nop 0;; nop 0;;"); +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ + + ssc(0, 0, 0, 0, SSC_CONSOLE_INIT); + + /* + * S.Eranian: extract the commandline argument from the + * simulator + * + * The expected format is as follows: + * + * kernelname args... + * + * Both are optional but you can't have the second one without the + * first. + */ + arglen = ssc((long) buffer, 0, 0, 0, SSC_GET_ARGS); + + kpath = "vmlinux"; + args = buffer; + if (arglen > 0) { + kpath = buffer; + while (*args != ' ' && *args != '\0') + ++args, --arglen; + if (*args == ' ') + *args++ = '\0', --arglen; + } + + if (arglen <= 0) { + args = ""; + arglen = 1; + } + + fd = ssc((long) kpath, 1, 0, 0, SSC_OPEN); + + if (fd < 0) { + cons_write(kpath); + cons_write(": file not found, reboot now\n"); + for(;;); + } + stat.fd = fd; + off = 0; + + req.len = sizeof(mem); + req.addr = (long) mem; + ssc(fd, 1, (long) &req, off, SSC_READ); + ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION); + + elf = (struct elfhdr *) mem; + if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) != 0) { + cons_write("not an ELF file\n"); + return; + } + if (elf->e_type != ET_EXEC) { + cons_write("not an ELF executable\n"); + return; + } + if (!elf_check_arch(elf->e_machine)) { + cons_write("kernel not for this processor\n"); + return; + } + + e_entry = elf->e_entry; + e_phnum = elf->e_phnum; + e_phoff = elf->e_phoff; + + cons_write("loading "); + cons_write(kpath); + cons_write("...\n"); + + for (i = 0; i < e_phnum; ++i) { + req.len = sizeof(*elf_phdr); + req.addr = (long) mem; + ssc(fd, 1, (long) &req, e_phoff, SSC_READ); + ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION); + if (stat.count != sizeof(*elf_phdr)) { + cons_write("failed to read phdr\n"); + return; + } + e_phoff += sizeof(*elf_phdr); + + elf_phdr = (struct elf_phdr *) mem; + req.len = elf_phdr->p_filesz; + req.addr = __pa(elf_phdr->p_vaddr); + ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ); + ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION); + memset((char *)__pa(elf_phdr->p_vaddr) + elf_phdr->p_filesz, 0, + elf_phdr->p_memsz - elf_phdr->p_filesz); + } + ssc(fd, 0, 0, 0, SSC_CLOSE); + + cons_write("starting kernel...\n"); + + /* fake an I/O base address: */ + asm volatile ("mov ar.k0=%0" :: "r"(0xffffc000000UL)); + + /* + * Install a translation register that identity maps the + * kernel's 256MB page. + */ + ia64_clear_ic(flags); + ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); + ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); + ia64_srlz_d(); + ia64_itr(0x3, 0, 1024*1024, + pte_val(mk_pte_phys(1024*1024, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), + _PAGE_SIZE_1M); + ia64_itr(0x3, 1, PAGE_OFFSET, + pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), + _PAGE_SIZE_256M); + ia64_srlz_i(); + + enter_virtual_mode(flags | IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT + | IA64_PSR_DFH | IA64_PSR_BN); + + sys_fw_init(args, arglen); + + ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS); + + /* + * Install the kernel's command line argument on ZERO_PAGE + * just after the botoparam structure. + * In case we don't have any argument just put \0 + */ + memcpy(((struct ia64_boot_param *)ZERO_PAGE_ADDR) + 1, args, arglen); + sp = __pa(&stack); + + asm volatile ("br.sptk.few %0" :: "b"(e_entry)); + + cons_write("kernel returned!\n"); + ssc(-1, 0, 0, 0, SSC_EXIT); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/boot/bootloader.lds linux/arch/ia64/boot/bootloader.lds --- v2.3.42/linux/arch/ia64/boot/bootloader.lds Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/boot/bootloader.lds Sun Feb 6 18:42:40 2000 @@ -0,0 +1,65 @@ +OUTPUT_FORMAT("elf64-ia64-little") +OUTPUT_ARCH(ia64) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x100000; + + _text = .; + .text : { *(__ivt_section) *(.text) } + _etext = .; + + /* Global data */ + _data = .; + .rodata : { *(.rodata) } + .data : { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } + __gp = ALIGN (8) + 0x200000; + .got : { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + + _bss = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : { *(.bss) *(COMMON) } + . = ALIGN(64 / 8); + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.3.42/linux/arch/ia64/config.in Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/config.in Sun Feb 6 18:42:40 2000 @@ -0,0 +1,172 @@ +mainmenu_name "Kernel configuration of Linux for IA-64 machines" + +mainmenu_option next_comment +comment 'General setup' + +choice 'IA-64 system type' \ + "Generic CONFIG_IA64_GENERIC \ + HP-simulator CONFIG_IA64_HP_SIM \ + SN1-simulator CONFIG_IA64_SGI_SN1_SIM \ + DIG-compliant CONFIG_IA64_DIG" Generic + +choice 'Kernel page size' \ + "4KB CONFIG_IA64_PAGE_SIZE_4KB \ + 8KB CONFIG_IA64_PAGE_SIZE_8KB \ + 16KB CONFIG_IA64_PAGE_SIZE_16KB \ + 64KB CONFIG_IA64_PAGE_SIZE_64KB" 16KB + +if [ "$CONFIG_IA64_DIG" = "y" ]; then + bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC + bool ' Enable SoftSDV hacks' CONFIG_IA64_SOFTSDV_HACKS n + bool ' Enable BigSur hacks' CONFIG_IA64_BIGSUR_HACKS y + bool ' Enable Lion hacks' CONFIG_IA64_LION_HACKS n + bool ' Emulate PAL/SAL/EFI firmware' CONFIG_IA64_FW_EMU n + bool ' Get PCI IRQ routing from firmware/ACPI' CONFIG_IA64_IRQ_ACPI y +fi + +if [ "$CONFIG_IA64_GENERIC" = "y" ]; then + define_bool CONFIG_IA64_SOFTSDV_HACKS y +fi + +if [ "$CONFIG_IA64_SGI_SN1_SIM" = "y" ]; then + define_bool CONFIG_NUMA y + define_bool CONFIG_IA64_SOFTSDV_HACKS y +fi + +define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /dev/kcore. + +bool 'SMP support' CONFIG_SMP n +bool 'Performance monitor support' CONFIG_PERFMON n + +bool 'Networking support' CONFIG_NET n +bool 'System V IPC' CONFIG_SYSVIPC n +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT n +bool 'Sysctl support' CONFIG_SYSCTL n +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC + +bool 'PCI support' CONFIG_PCI n +source drivers/pci/Config.in + +source drivers/pcmcia/Config.in + +mainmenu_option next_comment + comment 'Code maturity level options' + bool 'Prompt for development and/or incomplete code/drivers' \ + CONFIG_EXPERIMENTAL n +endmenu + +mainmenu_option next_comment + comment 'Loadable module support' + bool 'Enable loadable module support' CONFIG_MODULES n + if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n + bool 'Kernel module loader' CONFIG_KMOD n + fi +endmenu + +source drivers/parport/Config.in + +endmenu + +source drivers/pnp/Config.in +source drivers/block/Config.in +source drivers/i2o/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in + bool 'Simulated SCSI disk' CONFIG_SCSI_SIM n +fi +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES n + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + fi + endmenu +fi + +source net/ax25/Config.in + +mainmenu_option next_comment +comment 'ISDN subsystem' + +tristate 'ISDN support' CONFIG_ISDN +if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in +fi +endmenu + +mainmenu_option next_comment +comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' + +bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI n +if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in +fi +endmenu + +source drivers/char/Config.in +source drivers/usb/Config.in +source drivers/misc/Config.in + +source fs/Config.in + +source fs/nls/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + bool 'VGA text console' CONFIG_VGA_CONSOLE n + if [ "$CONFIG_FB" = "y" ]; then + define_bool CONFIG_PCI_CONSOLE y + fi + source drivers/video/Config.in + endmenu +fi + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel support for IA-32 emulation' CONFIG_IA32_SUPPORT + tristate 'Kernel FP software completion' CONFIG_MATHEMU +else + define_bool CONFIG_MATHEMU y +fi + +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ n +bool 'Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK n +bool 'Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG n +bool 'Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ n +bool 'Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS n +bool 'Built-in Kernel Debugger support' CONFIG_KDB +if [ "$CONFIG_KDB" = "y" ]; then + bool 'Compile the kernel with frame pointers' CONFIG_KDB_FRAMEPTR + int 'KDB Kernel Symbol Table size?' CONFIG_KDB_STBSIZE 10000 +fi + +endmenu diff -u --recursive --new-file v2.3.42/linux/arch/ia64/defconfig linux/arch/ia64/defconfig --- v2.3.42/linux/arch/ia64/defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/defconfig Sun Feb 6 18:42:40 2000 @@ -0,0 +1,146 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# General setup +# +CONFIG_IA64_SIM=y +CONFIG_PCI=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PCI_OLD_PROC=y +# CONFIG_NET is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_BINFMT_ELF is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_BINFMT_JAVA is not set +# CONFIG_BINFMT_EM86 is not set +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set +# CONFIG_SCSI_G_NCR5380_PORT is not set +# CONFIG_SCSI_G_NCR5380_MEM is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_VIDEO_DEV is not set +# CONFIG_NVRAM is not set +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_FT_NORMAL_DEBUG is not set +# CONFIG_FT_FULL_DEBUG is not set +# CONFIG_FT_NO_TRACE is not set +# CONFIG_FT_NO_TRACE_AT_ALL is not set +# CONFIG_FT_STD_FDC is not set +# CONFIG_FT_MACH2 is not set +# CONFIG_FT_PROBE_FC10 is not set +# CONFIG_FT_ALT_FDC is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_PROC_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_ADFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +# CONFIG_MATHEMU is not set +# CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.3.42/linux/arch/ia64/dig/Makefile linux/arch/ia64/dig/Makefile --- v2.3.42/linux/arch/ia64/dig/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/dig/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,24 @@ +# +# ia64/platform/dig/Makefile +# +# Copyright (C) 1999 Silicon Graphics, Inc. +# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) +# + +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + +all: dig.a + +O_TARGET = dig.a +O_OBJS = iosapic.o setup.o + +ifeq ($(CONFIG_IA64_GENERIC),y) +O_OBJS += machvec.o +endif + +clean:: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/dig/iosapic.c linux/arch/ia64/dig/iosapic.c --- v2.3.42/linux/arch/ia64/dig/iosapic.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/dig/iosapic.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,553 @@ +/* + * Streamlined APIC support. + * + * Copyright (C) 1999 Intel Corp. + * Copyright (C) 1999 Asit Mallick + * Copyright (C) 1999-2000 Hewlett-Packard Co. + * Copyright (C) 1999-2000 David Mosberger-Tang + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999,2000 Walt Drummond + */ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG_IRQ_ROUTING + +/* + * IRQ vectors 0..15 are treated as the legacy interrupts of the PC-AT + * platform. No new drivers should ever ask for specific irqs, but we + * provide compatibility here in case there is an old driver that does + * ask for specific irqs (serial, keyboard, stuff like that). Since + * IA-64 doesn't allow irq 0..15 to be used for external interrupts + * anyhow, this in no way prevents us from doing the Right Thing + * with new drivers. + */ +struct iosapic_vector iosapic_vector[NR_IRQS] = { + [0 ... NR_IRQS-1] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } +}; + +#ifndef CONFIG_IA64_IRQ_ACPI +/* + * Defines the default interrupt routing information for the LION platform + * XXX - this information should be obtained from the ACPI and hardcoded since + * we do not have ACPI AML support. + */ + +struct intr_routing_entry intr_routing[] = { + {0,0,0,2,0,0,0,0}, + {0,0,1,1,0,0,0,0}, + {0,0,2,0xff,0,0,0,0}, + {0,0,3,3,0,0,0,0}, + {0,0,4,4,0,0,0,0}, + {0,0,5,5,0,0,0,0}, + {0,0,6,6,0,0,0,0}, + {0,0,7,7,0,0,0,0}, + {0,0,8,8,0,0,0,0}, + {0,0,9,9,0,0,0,0}, + {0,0,10,10,0,0,0,0}, + {0,0,11,11,0,0,0,0}, + {0,0,12,12,0,0,0,0}, + {0,0,13,13,0,0,0,0}, + {0,0,14,14,0,0,0,0}, + {0,0,15,15,0,0,0,0}, +#ifdef CONFIG_IA64_LION_HACKS + {1, 0, 0x04, 16, 0, 0, 1, 1}, /* bus 0, device id 1, INTA */ + {1, 0, 0x05, 26, 0, 0, 1, 1}, /* bus 0, device id 1, INTB */ + {1, 0, 0x06, 36, 0, 0, 1, 1}, /* bus 0, device id 1, INTC */ + {1, 0, 0x07, 42, 0, 0, 1, 1}, /* bus 0, device id 1, INTD */ + + {1, 0, 0x08, 17, 0, 0, 1, 1}, /* bus 0, device id 2, INTA */ + {1, 0, 0x09, 27, 0, 0, 1, 1}, /* bus 0, device id 2, INTB */ + {1, 0, 0x0a, 37, 0, 0, 1, 1}, /* bus 0, device id 2, INTC */ + {1, 0, 0x0b, 42, 0, 0, 1, 1}, /* bus 0, device id 2, INTD */ + + {1, 0, 0x0f, 50, 0, 0, 1, 1}, /* bus 0, device id 3, INTD */ + + {1, 0, 0x14, 51, 0, 0, 1, 1}, /* bus 0, device id 5, INTA */ + + {1, 0, 0x18, 49, 0, 0, 1, 1}, /* bus 0, device id 6, INTA */ + + {1, 1, 0x04, 18, 0, 0, 1, 1}, /* bus 1, device id 1, INTA */ + {1, 1, 0x05, 28, 0, 0, 1, 1}, /* bus 1, device id 1, INTB */ + {1, 1, 0x06, 38, 0, 0, 1, 1}, /* bus 1, device id 1, INTC */ + {1, 1, 0x07, 43, 0, 0, 1, 1}, /* bus 1, device id 1, INTD */ + + {1, 1, 0x08, 48, 0, 0, 1, 1}, /* bus 1, device id 2, INTA */ + + {1, 1, 0x0c, 19, 0, 0, 1, 1}, /* bus 1, device id 3, INTA */ + {1, 1, 0x0d, 29, 0, 0, 1, 1}, /* bus 1, device id 3, INTB */ + {1, 1, 0x0e, 38, 0, 0, 1, 1}, /* bus 1, device id 3, INTC */ + {1, 1, 0x0f, 44, 0, 0, 1, 1}, /* bus 1, device id 3, INTD */ + + {1, 1, 0x10, 20, 0, 0, 1, 1}, /* bus 1, device id 4, INTA */ + {1, 1, 0x11, 30, 0, 0, 1, 1}, /* bus 1, device id 4, INTB */ + {1, 1, 0x12, 39, 0, 0, 1, 1}, /* bus 1, device id 4, INTC */ + {1, 1, 0x13, 45, 0, 0, 1, 1}, /* bus 1, device id 4, INTD */ + + {1, 2, 0x04, 21, 0, 0, 1, 1}, /* bus 2, device id 1, INTA */ + {1, 2, 0x05, 31, 0, 0, 1, 1}, /* bus 2, device id 1, INTB */ + {1, 2, 0x06, 39, 0, 0, 1, 1}, /* bus 2, device id 1, INTC */ + {1, 2, 0x07, 45, 0, 0, 1, 1}, /* bus 2, device id 1, INTD */ + + {1, 2, 0x08, 22, 0, 0, 1, 1}, /* bus 2, device id 2, INTA */ + {1, 2, 0x09, 32, 0, 0, 1, 1}, /* bus 2, device id 2, INTB */ + {1, 2, 0x0a, 40, 0, 0, 1, 1}, /* bus 2, device id 2, INTC */ + {1, 2, 0x0b, 46, 0, 0, 1, 1}, /* bus 2, device id 2, INTD */ + + {1, 2, 0x0c, 23, 0, 0, 1, 1}, /* bus 2, device id 3, INTA */ + {1, 2, 0x0d, 33, 0, 0, 1, 1}, /* bus 2, device id 3, INTB */ + {1, 2, 0x0e, 40, 0, 0, 1, 1}, /* bus 2, device id 3, INTC */ + {1, 2, 0x0f, 46, 0, 0, 1, 1}, /* bus 2, device id 3, INTD */ + + {1, 3, 0x04, 24, 0, 0, 1, 1}, /* bus 3, device id 1, INTA */ + {1, 3, 0x05, 34, 0, 0, 1, 1}, /* bus 3, device id 1, INTB */ + {1, 3, 0x06, 41, 0, 0, 1, 1}, /* bus 3, device id 1, INTC */ + {1, 3, 0x07, 47, 0, 0, 1, 1}, /* bus 3, device id 1, INTD */ + + {1, 3, 0x08, 25, 0, 0, 1, 1}, /* bus 3, device id 2, INTA */ + {1, 3, 0x09, 35, 0, 0, 1, 1}, /* bus 3, device id 2, INTB */ + {1, 3, 0x0a, 41, 0, 0, 1, 1}, /* bus 3, device id 2, INTC */ + {1, 3, 0x0b, 47, 0, 0, 1, 1}, /* bus 3, device id 2, INTD */ +#else + /* + * BigSur platform, bus 0, device 1,2,4 and bus 1 device 0-3 + */ + {1,1,0x0,19,0,0,1,1}, /* bus 1, device id 0, INTA */ + {1,1,0x1,18,0,0,1,1}, /* bus 1, device id 0, INTB */ + {1,1,0x2,17,0,0,1,1}, /* bus 1, device id 0, INTC */ + {1,1,0x3,16,0,0,1,1}, /* bus 1, device id 0, INTD */ + + {1,1,0x4,23,0,0,1,1}, /* bus 1, device id 1, INTA */ + {1,1,0x5,22,0,0,1,1}, /* bus 1, device id 1, INTB */ + {1,1,0x6,21,0,0,1,1}, /* bus 1, device id 1, INTC */ + {1,1,0x7,20,0,0,1,1}, /* bus 1, device id 1, INTD */ + + {1,1,0x8,27,0,0,1,1}, /* bus 1, device id 2, INTA */ + {1,1,0x9,26,0,0,1,1}, /* bus 1, device id 2, INTB */ + {1,1,0xa,25,0,0,1,1}, /* bus 1, device id 2, INTC */ + {1,1,0xb,24,0,0,1,1}, /* bus 1, device id 2, INTD */ + + {1,1,0xc,31,0,0,1,1}, /* bus 1, device id 3, INTA */ + {1,1,0xd,30,0,0,1,1}, /* bus 1, device id 3, INTB */ + {1,1,0xe,29,0,0,1,1}, /* bus 1, device id 3, INTC */ + {1,1,0xf,28,0,0,1,1}, /* bus 1, device id 3, INTD */ + + {1,0,0x4,35,0,0,1,1}, /* bus 0, device id 1, INTA */ + {1,0,0x5,34,0,0,1,1}, /* bus 0, device id 1, INTB */ + {1,0,0x6,33,0,0,1,1}, /* bus 0, device id 1, INTC */ + {1,0,0x7,32,0,0,1,1}, /* bus 0, device id 1, INTD */ + + {1,0,0x8,39,0,0,1,1}, /* bus 0, device id 2, INTA */ + {1,0,0x9,38,0,0,1,1}, /* bus 0, device id 2, INTB */ + {1,0,0xa,37,0,0,1,1}, /* bus 0, device id 2, INTC */ + {1,0,0xb,36,0,0,1,1}, /* bus 0, device id 2, INTD */ + + {1,0,0x10,43,0,0,1,1}, /* bus 0, device id 4, INTA */ + {1,0,0x11,42,0,0,1,1}, /* bus 0, device id 4, INTB */ + {1,0,0x12,41,0,0,1,1}, /* bus 0, device id 4, INTC */ + {1,0,0x13,40,0,0,1,1}, /* bus 0, device id 4, INTD */ + + {1,0,0x14,17,0,0,1,1}, /* bus 0, device id 5, INTA */ + {1,0,0x18,18,0,0,1,1}, /* bus 0, device id 6, INTA */ + {1,0,0x1c,19,0,0,1,1}, /* bus 0, device id 7, INTA */ +#endif + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, +}; + +int +iosapic_get_PCI_irq_vector(int bus, int slot, int pci_pin) +{ + int i = -1; + + while (intr_routing[++i].srcbus != 0xff) { + if (intr_routing[i].srcbus == BUS_PCI) { + if ((intr_routing[i].srcbusirq == ((slot << 2) | pci_pin)) + && (intr_routing[i].srcbusno == bus)) { + return(intr_routing[i].iosapic_pin); + } + } + } + return -1; +} + +#else /* CONFIG_IA64_IRQ_ACPI */ + +/* + * find the IRQ in the IOSAPIC map for the PCI device on bus/slot/pin + */ +int +iosapic_get_PCI_irq_vector(int bus, int slot, int pci_pin) +{ + int i; + + for (i = 0; i < NR_IRQS; i++) { + if ((iosapic_bustype(i) == BUS_PCI) && + (iosapic_bus(i) == bus) && + (iosapic_busdata(i) == ((slot << 16) | pci_pin))) { + return i; + } + } + + return -1; +} +#endif /* !CONFIG_IA64_IRQ_ACPI */ + +static void +set_rte (unsigned long iosapic_addr, int entry, int pol, int trigger, int delivery, + long dest, int vector) +{ + int low32; + int high32; + + low32 = ((pol << IO_SAPIC_POLARITY_SHIFT) | + (trigger << IO_SAPIC_TRIGGER_SHIFT) | + (delivery << IO_SAPIC_DELIVERY_SHIFT) | + vector); + + /* dest contains both id and eid */ + high32 = (dest << IO_SAPIC_DEST_SHIFT); + + /* + * program the rte + */ + writel(IO_SAPIC_RTE_HIGH(entry), iosapic_addr + IO_SAPIC_REG_SELECT); + writel(high32, iosapic_addr + IO_SAPIC_WINDOW); + writel(IO_SAPIC_RTE_LOW(entry), iosapic_addr + IO_SAPIC_REG_SELECT); + writel(low32, iosapic_addr + IO_SAPIC_WINDOW); +} + + +static void +enable_pin (unsigned int pin, unsigned long iosapic_addr) +{ + int low32; + + writel(IO_SAPIC_RTE_LOW(pin), iosapic_addr + IO_SAPIC_REG_SELECT); + low32 = readl(iosapic_addr + IO_SAPIC_WINDOW); + + low32 &= ~(1 << IO_SAPIC_MASK_SHIFT); /* Zero only the mask bit */ + writel(low32, iosapic_addr + IO_SAPIC_WINDOW); +} + + +static void +disable_pin (unsigned int pin, unsigned long iosapic_addr) +{ + int low32; + + writel(IO_SAPIC_RTE_LOW(pin), iosapic_addr + IO_SAPIC_REG_SELECT); + low32 = readl(iosapic_addr + IO_SAPIC_WINDOW); + + low32 |= (1 << IO_SAPIC_MASK_SHIFT); /* Set only the mask bit */ + writel(low32, iosapic_addr + IO_SAPIC_WINDOW); +} + +#define iosapic_shutdown_irq iosapic_disable_irq + +static void +iosapic_enable_irq (unsigned int irq) +{ + int pin = iosapic_pin(irq); + + if (pin < 0) + /* happens during irq auto probing... */ + return; + enable_pin(pin, iosapic_addr(irq)); +} + +static void +iosapic_disable_irq (unsigned int irq) +{ + int pin = iosapic_pin(irq); + + if (pin < 0) + return; + disable_pin(pin, iosapic_addr(irq)); +} + +unsigned int +iosapic_version(unsigned long base_addr) +{ + /* + * IOSAPIC Version Register return 32 bit structure like: + * { + * unsigned int version : 8; + * unsigned int reserved1 : 8; + * unsigned int pins : 8; + * unsigned int reserved2 : 8; + * } + */ + writel(IO_SAPIC_VERSION, base_addr + IO_SAPIC_REG_SELECT); + return readl(IO_SAPIC_WINDOW + base_addr); +} + +static int +iosapic_handle_irq (unsigned int irq, struct pt_regs *regs) +{ + struct irqaction *action = 0; + struct irq_desc *id = irq_desc + irq; + unsigned int status; + int retval; + + spin_lock(&irq_controller_lock); + { + status = id->status; + + /* do we need to do something IOSAPIC-specific to ACK the irq here??? */ + /* Yes, but only level-triggered interrupts. We'll do that later */ + if ((status & IRQ_INPROGRESS) == 0 && (status & IRQ_ENABLED) != 0) { + action = id->action; + status |= IRQ_INPROGRESS; + } + id->status = status & ~(IRQ_REPLAY | IRQ_WAITING); + } + spin_unlock(&irq_controller_lock); + + if (!action) { + if (!(id->status & IRQ_AUTODETECT)) + printk("iosapic_handle_irq: unexpected interrupt %u;" + "disabling it (status=%x)\n", irq, id->status); + /* + * If we don't have a handler, disable the pin so we + * won't get any further interrupts (until + * re-enabled). --davidm 99/12/17 + */ + iosapic_disable_irq(irq); + return 0; + } + + retval = invoke_irq_handlers (irq, regs, action); + + if (iosapic_trigger(irq) == IO_SAPIC_LEVEL) /* ACK Level trigger interrupts */ + writel(irq, iosapic_addr(irq) + IO_SAPIC_EOI); + + spin_lock(&irq_controller_lock); + { + status = (id->status & ~IRQ_INPROGRESS); + id->status = status; + } + spin_unlock(&irq_controller_lock); + + return retval; +} + +void __init +iosapic_init (unsigned long addr) +{ + int i; +#ifdef CONFIG_IA64_IRQ_ACPI + struct pci_vector_struct *vectors; + int irq; +#else + int vector; +#endif + + /* + * Disable all local interrupts + */ + + ia64_set_itv(0, 1); + ia64_set_lrr0(0, 1); + ia64_set_lrr1(0, 1); + + /* + * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support + * enabled. + */ + + outb(0xff, 0xA1); + outb(0xff, 0x21); + +#if defined(CONFIG_IA64_SOFTSDV_HACKS) + memset(iosapic_vector, 0x0, sizeof(iosapic_vector)); + for (i = 0; i < NR_IRQS; i++) { + iosapic_pin(i) = 0xff; + iosapic_addr(i) = (unsigned long) ioremap(IO_SAPIC_DEFAULT_ADDR, 0); + } + /* XXX this should come from systab or some such: */ + iosapic_pin(TIMER_IRQ) = 5; /* System Clock Interrupt */ + iosapic_pin(0x40) = 3; /* Keyboard */ + iosapic_pin(0x92) = 9; /* COM1 Serial Port */ + iosapic_pin(0x80) = 4; /* Periodic Interrupt */ + iosapic_pin(0xc0) = 2; /* Mouse */ + iosapic_pin(0xe0) = 1; /* IDE Disk */ + iosapic_pin(0xf0) = 6; /* E-IDE CDROM */ + iosapic_pin(0xa0) = 10; /* Real PCI Interrupt */ +#elif !defined(CONFIG_IA64_IRQ_ACPI) + /* + * For systems where the routing info in ACPI is + * unavailable/wrong, use the intr_routing information to + * initialize the iosapic array + */ + i = -1; + while (intr_routing[++i].srcbus != 0xff) { + if (intr_routing[i].srcbus == BUS_ISA) { + vector = map_legacy_irq(intr_routing[i].srcbusirq); + } else if (intr_routing[i].srcbus == BUS_PCI) { + vector = intr_routing[i].iosapic_pin; + } else { + printk("unknown bus type %d for intr_routing[%d]\n", + intr_routing[i].srcbus, i); + continue; + } + iosapic_pin(vector) = intr_routing[i].iosapic_pin; + iosapic_dmode(vector) = intr_routing[i].mode; + iosapic_polarity(vector) = intr_routing[i].polarity; + iosapic_trigger(vector) = intr_routing[i].trigger; +# ifdef DEBUG_IRQ_ROUTING + printk("irq[0x%x(0x%x)]:0x%x, %d, %d, %d\n", vector, intr_routing[i].srcbusirq, + iosapic_pin(vector), iosapic_dmode(vector), iosapic_polarity(vector), + iosapic_trigger(vector)); +# endif + } +#else /* !defined(CONFIG_IA64_SOFTSDV_HACKS) && !defined(CONFIG_IA64_IRQ_ACPI) */ + /* + * Map the legacy ISA devices into the IOAPIC data; We'll override these + * later with data from the ACPI Interrupt Source Override table. + * + * Huh, the Lion w/ FPSWA firmware has entries for _all_ of the legacy IRQs, + * including those that are not different from PC/AT standard. I don't know + * if this is a bug in the other firmware or not. I'm going to leave this code + * here, so that this works on BigSur but will go ask Intel. --wfd 2000-Jan-19 + * + */ + for (i =0 ; i < IA64_MIN_VECTORED_IRQ; i++) { + irq = map_legacy_irq(i); + iosapic_pin(irq) = i; + iosapic_bus(irq) = BUS_ISA; + iosapic_busdata(irq) = 0; + iosapic_dmode(irq) = IO_SAPIC_LOWEST_PRIORITY; + iosapic_trigger(irq) = IO_SAPIC_EDGE; + iosapic_polarity(irq) = IO_SAPIC_POL_HIGH; +#ifdef DEBUG_IRQ_ROUTING + printk("ISA: IRQ %02x -> Vector %02x IOSAPIC Pin %d\n", i, irq, iosapic_pin(irq)); +#endif + } + + /* + * Map the PCI Interrupt data into the ACPI IOSAPIC data using + * the info that the bootstrap loader passed to us. + */ + ia64_boot_param.pci_vectors = (__u64) __va(ia64_boot_param.pci_vectors); + vectors = (struct pci_vector_struct *) ia64_boot_param.pci_vectors; + for (i = 0; i < ia64_boot_param.num_pci_vectors; i++) { + irq = map_legacy_irq(vectors[i].irq); + + iosapic_bustype(irq) = BUS_PCI; + iosapic_pin(irq) = irq - iosapic_baseirq(irq); + iosapic_bus(irq) = vectors[i].bus; + /* + * Map the PCI slot and pin data into iosapic_busdata() + */ + iosapic_busdata(irq) = (vectors[i].pci_id & 0xffff0000) | vectors[i].pin; + + /* Default settings for PCI */ + iosapic_dmode(irq) = IO_SAPIC_LOWEST_PRIORITY; + iosapic_trigger(irq) = IO_SAPIC_LEVEL; + iosapic_polarity(irq) = IO_SAPIC_POL_LOW; + +#ifdef DEBUG_IRQ_ROUTING + printk("PCI: BUS %d Slot %x Pin %x IRQ %02x --> Vector %02x IOSAPIC Pin %d\n", + vectors[i].bus, vectors[i].pci_id>>16, vectors[i].pin, vectors[i].irq, + irq, iosapic_pin(irq)); +#endif + } +#endif /* !CONFIG_IA64_IRQ_ACPI */ +} + +static void +iosapic_startup_irq (unsigned int irq) +{ + int pin; + + if (irq == TIMER_IRQ) + return; + pin = iosapic_pin(irq); + if (pin < 0) + /* happens during irq auto probing... */ + return; + set_rte(iosapic_addr(irq), pin, iosapic_polarity(irq), iosapic_trigger(irq), + iosapic_dmode(irq), (ia64_get_lid() >> 16) & 0xffff, irq); + enable_pin(pin, iosapic_addr(irq)); +} + +struct hw_interrupt_type irq_type_iosapic = { + "IOSAPIC", + iosapic_init, + iosapic_startup_irq, + iosapic_shutdown_irq, + iosapic_handle_irq, + iosapic_enable_irq, + iosapic_disable_irq +}; + +void +dig_irq_init (struct irq_desc desc[NR_IRQS]) +{ + int i; + + /* + * Claim all non-legacy irq vectors as ours unless they're + * claimed by someone else already (e.g., timer or IPI are + * handled internally). + */ + for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) { + if (irq_desc[i].handler == &irq_type_default) + irq_desc[i].handler = &irq_type_iosapic; + } +} + +void +dig_pci_fixup (void) +{ + struct pci_dev *dev; + int irq; + unsigned char pin; + + pci_for_each_dev(dev) { + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + pin--; /* interrupt pins are numbered starting from 1 */ + irq = iosapic_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), + pin); + if (irq < 0 && dev->bus->parent) { /* go back to the bridge */ + struct pci_dev * bridge = dev->bus->self; + + /* do the bridge swizzle... */ + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + irq = iosapic_get_PCI_irq_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); + if (irq >= 0) + printk(KERN_WARNING + "PCI: using PPB(B%d,I%d,P%d) to get irq %02x\n", + bridge->bus->number, PCI_SLOT(bridge->devfn), + pin, irq); + } + if (irq >= 0) { + printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %02x\n", + dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); + dev->irq = irq; + } + } + /* + * Nothing to fixup + * Fix out-of-range IRQ numbers + */ + if (dev->irq >= NR_IRQS) + dev->irq = 15; /* Spurious interrupts */ + } +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/dig/machvec.c linux/arch/ia64/dig/machvec.c --- v2.3.42/linux/arch/ia64/dig/machvec.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/dig/machvec.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,4 @@ +#include +#include + +MACHVEC_DEFINE(dig) diff -u --recursive --new-file v2.3.42/linux/arch/ia64/dig/setup.c linux/arch/ia64/dig/setup.c --- v2.3.42/linux/arch/ia64/dig/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/dig/setup.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,93 @@ +/* + * Platform dependent support for Intel SoftSDV simulator. + * + * Copyright (C) 1999 Intel Corp. + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999 Vijay Chander + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_IA64_FW_EMU +# include "../../kernel/fw-emu.c" +#endif + +/* + * This is here so we can use the CMOS detection in ide-probe.c to + * determine what drives are present. In theory, we don't need this + * as the auto-detection could be done via ide-probe.c:do_probe() but + * in practice that would be much slower, which is painful when + * running in the simulator. Note that passing zeroes in DRIVE_INFO + * is sufficient (the IDE driver will autodetect the drive geometry). + */ +char drive_info[4*16]; + +unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */ + +void __init +dig_setup (char **cmdline_p) +{ + unsigned int orig_x, orig_y, num_cols, num_rows, font_height; + + /* + * This assumes that the EFI partition is physical disk 1 + * partition 1 and the Linux root disk is physical disk 1 + * partition 2. + */ +#ifdef CONFIG_IA64_LION_HACKS + /* default to /dev/sda2 on Lion... */ + ROOT_DEV = to_kdev_t(0x0802); /* default to second partition on first drive */ +#else + /* default to /dev/dha2 on BigSur... */ + ROOT_DEV = to_kdev_t(0x0302); /* default to second partition on first drive */ +#endif + +#ifdef CONFIG_SMP + init_smp_config(); +#endif + + memset(&screen_info, 0, sizeof(screen_info)); + + if (!ia64_boot_param.console_info.num_rows + || !ia64_boot_param.console_info.num_cols) + { + printk("dig_setup: warning: invalid screen-info, guessing 80x25\n"); + orig_x = 0; + orig_y = 0; + num_cols = 80; + num_rows = 25; + font_height = 16; + } else { + orig_x = ia64_boot_param.console_info.orig_x; + orig_y = ia64_boot_param.console_info.orig_y; + num_cols = ia64_boot_param.console_info.num_cols; + num_rows = ia64_boot_param.console_info.num_rows; + font_height = 400 / num_rows; + } + + screen_info.orig_x = orig_x; + screen_info.orig_y = orig_y; + screen_info.orig_video_cols = num_cols; + screen_info.orig_video_lines = num_rows; + screen_info.orig_video_points = font_height; + screen_info.orig_video_mode = 3; /* XXX fake */ + screen_info.orig_video_isVGA = 1; /* XXX fake */ + screen_info.orig_video_ega_bx = 3; /* XXX fake */ +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/hp/Makefile linux/arch/ia64/hp/Makefile --- v2.3.42/linux/arch/ia64/hp/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/hp/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,19 @@ +# +# ia64/platform/hp/Makefile +# +# Copyright (C) 1999 Silicon Graphics, Inc. +# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) +# + +all: hp.a + +O_TARGET = hp.a +O_OBJS = hpsim_console.o hpsim_irq.o hpsim_setup.o + +ifeq ($(CONFIG_IA64_GENERIC),y) +O_OBJS += hpsim_machvec.o +endif + +clean:: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/hp/hpsim_console.c linux/arch/ia64/hp/hpsim_console.c --- v2.3.42/linux/arch/ia64/hp/hpsim_console.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/hp/hpsim_console.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,78 @@ +/* + * Platform dependent support for HP simulator. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1999 Vijay Chander + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "hpsim_ssc.h" + +static int simcons_init (struct console *, char *); +static void simcons_write (struct console *, const char *, unsigned); +static int simcons_wait_key (struct console *); +static kdev_t simcons_console_device (struct console *); + +struct console hpsim_cons = { + "simcons", + simcons_write, /* write */ + NULL, /* read */ + simcons_console_device, /* device */ + simcons_wait_key, /* wait_key */ + NULL, /* unblank */ + simcons_init, /* setup */ + CON_PRINTBUFFER, /* flags */ + -1, /* index */ + 0, /* cflag */ + NULL /* next */ +}; + +static int +simcons_init (struct console *cons, char *options) +{ + return 0; +} + +static void +simcons_write (struct console *cons, const char *buf, unsigned count) +{ + unsigned long ch; + + while (count-- > 0) { + ch = *buf++; + ia64_ssc(ch, 0, 0, 0, SSC_PUTCHAR); + if (ch == '\n') + ia64_ssc('\r', 0, 0, 0, SSC_PUTCHAR); + } +} + +static int +simcons_wait_key (struct console *cons) +{ + char ch; + + do { + ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); + } while (ch == '\0'); + return ch; +} + +static kdev_t +simcons_console_device (struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/hp/hpsim_irq.c linux/arch/ia64/hp/hpsim_irq.c --- v2.3.42/linux/arch/ia64/hp/hpsim_irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/hp/hpsim_irq.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,83 @@ +/* + * Platform dependent support for HP simulator. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1999 Vijay Chander + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +static int +irq_hp_sim_handle_irq (unsigned int irq, struct pt_regs *regs) +{ + struct irqaction *action = 0; + struct irq_desc *id = irq_desc + irq; + unsigned int status; + int retval; + + spin_lock(&irq_controller_lock); + { + status = id->status; + if ((status & IRQ_INPROGRESS) == 0 && (status & IRQ_ENABLED) != 0) { + action = id->action; + status |= IRQ_INPROGRESS; + } + id->status = status & ~(IRQ_REPLAY | IRQ_WAITING); + } + spin_unlock(&irq_controller_lock); + + if (!action) { + if (!(id->status & IRQ_AUTODETECT)) + printk("irq_hpsim_handle_irq: unexpected interrupt %u\n", irq); + return 0; + } + + retval = invoke_irq_handlers(irq, regs, action); + + spin_lock(&irq_controller_lock); + { + id->status &= ~IRQ_INPROGRESS; + } + spin_unlock(&irq_controller_lock); + + return retval; +} + +static void +irq_hp_sim_noop (unsigned int irq) +{ +} + +static struct hw_interrupt_type irq_type_hp_sim = { + "hp_sim", + (void (*)(unsigned long)) irq_hp_sim_noop, /* init */ + irq_hp_sim_noop, /* startup */ + irq_hp_sim_noop, /* shutdown */ + irq_hp_sim_handle_irq, /* handle */ + irq_hp_sim_noop, /* enable */ + irq_hp_sim_noop, /* disable */ +}; + +void +hpsim_irq_init (struct irq_desc desc[NR_IRQS]) +{ + int i; + + for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) { + irq_desc[i].handler = &irq_type_hp_sim; + } +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/hp/hpsim_machvec.c linux/arch/ia64/hp/hpsim_machvec.c --- v2.3.42/linux/arch/ia64/hp/hpsim_machvec.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/hp/hpsim_machvec.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,4 @@ +#include +#include + +MACHVEC_DEFINE(hpsim) diff -u --recursive --new-file v2.3.42/linux/arch/ia64/hp/hpsim_setup.c linux/arch/ia64/hp/hpsim_setup.c --- v2.3.42/linux/arch/ia64/hp/hpsim_setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/hp/hpsim_setup.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,71 @@ +/* + * Platform dependent support for HP simulator. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1999 Vijay Chander + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "hpsim_ssc.h" + +extern struct console hpsim_cons; + +/* + * Simulator system call. + */ +inline long +ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr) +{ +#ifdef __GCC_DOESNT_KNOW_IN_REGS__ + register long in0 asm ("r32") = arg0; + register long in1 asm ("r33") = arg1; + register long in2 asm ("r34") = arg2; + register long in3 asm ("r35") = arg3; +#else + register long in0 asm ("in0") = arg0; + register long in1 asm ("in1") = arg1; + register long in2 asm ("in2") = arg2; + register long in3 asm ("in3") = arg3; +#endif + register long r8 asm ("r8"); + register long r15 asm ("r15") = nr; + + asm volatile ("break 0x80001" + : "=r"(r8) + : "r"(r15), "r"(in0), "r"(in1), "r"(in2), "r"(in3)); + return r8; +} + +void +ia64_ssc_connect_irq (long intr, long irq) +{ + ia64_ssc(intr, irq, 0, 0, SSC_CONNECT_INTERRUPT); +} + +void +ia64_ctl_trace (long on) +{ + ia64_ssc(on, 0, 0, 0, SSC_CTL_TRACE); +} + +void __init +hpsim_setup (char **cmdline_p) +{ + ROOT_DEV = to_kdev_t(0x0801); /* default to first SCSI drive */ + + register_console (&hpsim_cons); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/hp/hpsim_ssc.h linux/arch/ia64/hp/hpsim_ssc.h --- v2.3.42/linux/arch/ia64/hp/hpsim_ssc.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/hp/hpsim_ssc.h Sun Feb 6 18:42:40 2000 @@ -0,0 +1,36 @@ +/* + * Platform dependent support for HP simulator. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1999 Vijay Chander + */ +#ifndef _IA64_PLATFORM_HPSIM_SSC_H +#define _IA64_PLATFORM_HPSIM_SSC_H + +/* Simulator system calls: */ + +#define SSC_CONSOLE_INIT 20 +#define SSC_GETCHAR 21 +#define SSC_PUTCHAR 31 +#define SSC_CONNECT_INTERRUPT 58 +#define SSC_GENERATE_INTERRUPT 59 +#define SSC_SET_PERIODIC_INTERRUPT 60 +#define SSC_GET_RTC 65 +#define SSC_EXIT 66 +#define SSC_LOAD_SYMBOLS 69 +#define SSC_GET_TOD 74 +#define SSC_CTL_TRACE 76 + +#define SSC_NETDEV_PROBE 100 +#define SSC_NETDEV_SEND 101 +#define SSC_NETDEV_RECV 102 +#define SSC_NETDEV_ATTACH 103 +#define SSC_NETDEV_DETACH 104 + +/* + * Simulator system call. + */ +extern long ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr); + +#endif /* _IA64_PLATFORM_HPSIM_SSC_H */ diff -u --recursive --new-file v2.3.42/linux/arch/ia64/ia32/Makefile linux/arch/ia64/ia32/Makefile --- v2.3.42/linux/arch/ia64/ia32/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/ia32/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,17 @@ +# +# Makefile for the ia32 kernel emulation subsystem. +# + +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + +all: ia32.o + +O_TARGET := ia32.o +O_OBJS := ia32_entry.o ia32_signal.o sys_ia32.o ia32_support.o binfmt_elf32.o + +clean:: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c --- v2.3.42/linux/arch/ia64/ia32/binfmt_elf32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/ia32/binfmt_elf32.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,180 @@ +/* + * IA-32 ELF support. + * + * Copyright (C) 1999 Arun Sharma + */ +#include +#include + +#include +#include + +#define CONFIG_BINFMT_ELF32 + +/* Override some function names */ +#undef start_thread +#define start_thread ia32_start_thread +#define init_elf_binfmt init_elf32_binfmt + +#undef CONFIG_BINFMT_ELF +#ifdef CONFIG_BINFMT_ELF32 +# define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32 +#endif + +#undef CONFIG_BINFMT_ELF_MODULE +#ifdef CONFIG_BINFMT_ELF32_MODULE +# define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE +#endif + +void ia64_elf32_init(struct pt_regs *regs); +#define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) + +#define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) + +/* Ugly but avoids duplication */ +#include "../../../fs/binfmt_elf.c" + +/* Global descriptor table */ +unsigned long *ia32_gdt_table, *ia32_tss; + +struct page * +put_shared_page(struct task_struct * tsk, struct page *page, unsigned long address) +{ + pgd_t * pgd; + pmd_t * pmd; + pte_t * pte; + + if (page_count(page) != 1) + printk("mem_map disagrees with %p at %08lx\n", page, address); + pgd = pgd_offset(tsk->mm, address); + pmd = pmd_alloc(pgd, address); + if (!pmd) { + __free_page(page); + oom(tsk); + return 0; + } + pte = pte_alloc(pmd, address); + if (!pte) { + __free_page(page); + oom(tsk); + return 0; + } + if (!pte_none(*pte)) { + pte_ERROR(*pte); + __free_page(page); + return 0; + } + flush_page_to_ram(page); + set_pte(pte, pte_mkwrite(mk_pte(page, PAGE_SHARED))); + /* no need for flush_tlb */ + return page; +} + +void ia64_elf32_init(struct pt_regs *regs) +{ + int nr; + + put_shared_page(current, mem_map + MAP_NR(ia32_gdt_table), IA32_PAGE_OFFSET); + if (PAGE_SHIFT <= IA32_PAGE_SHIFT) + put_shared_page(current, mem_map + MAP_NR(ia32_tss), IA32_PAGE_OFFSET + PAGE_SIZE); + + nr = smp_processor_id(); + + /* Do all the IA-32 setup here */ + + /* CS descriptor */ + __asm__("mov ar.csd = %0" : /* no outputs */ + : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, + 3L, 1L, 1L, 1L)); + /* SS descriptor */ + __asm__("mov ar.ssd = %0" : /* no outputs */ + : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, + 3L, 1L, 1L, 1L)); + /* EFLAGS */ + __asm__("mov ar.eflag = %0" : /* no outputs */ : "r" (IA32_EFLAG)); + + /* Control registers */ + __asm__("mov ar.cflg = %0" + : /* no outputs */ + : "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); + __asm__("mov ar.fsr = %0" + : /* no outputs */ + : "r" ((ulong)IA32_FSR_DEFAULT)); + __asm__("mov ar.fcr = %0" + : /* no outputs */ + : "r" ((ulong)IA32_FCR_DEFAULT)); + __asm__("mov ar.fir = r0"); + __asm__("mov ar.fdr = r0"); + /* TSS */ + __asm__("mov ar.k1 = %0" + : /* no outputs */ + : "r" IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE, + 0x1FFFL, 0xBL, 1L, + 3L, 1L, 1L, 1L)); + + /* Get the segment selectors right */ + regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ + regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) + | (__USER_DS << 16) | __USER_CS; + + /* Setup other segment descriptors - ESD, DSD, FSD, GSD */ + regs->r24 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); + regs->r27 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); + regs->r28 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); + regs->r29 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); + + /* Setup the LDT and GDT */ + regs->r30 = ia32_gdt_table[_LDT(nr)]; + regs->r31 = IA64_SEG_DESCRIPTOR(0xc0000000L, 0x400L, 0x3L, 1L, 3L, + 1L, 1L, 1L); + + /* Clear psr.ac */ + regs->cr_ipsr &= ~IA64_PSR_AC; + + regs->loadrs = 0; +} + +#undef STACK_TOP +#define STACK_TOP ((IA32_PAGE_OFFSET/3) * 2) + +int ia32_setup_arg_pages(struct linux_binprm *bprm) +{ + unsigned long stack_base; + struct vm_area_struct *mpnt; + int i; + + stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; + + bprm->p += stack_base; + if (bprm->loader) + bprm->loader += stack_base; + bprm->exec += stack_base; + + mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!mpnt) + return -ENOMEM; + + { + mpnt->vm_mm = current->mm; + mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; + mpnt->vm_end = STACK_TOP; + mpnt->vm_page_prot = PAGE_COPY; + mpnt->vm_flags = VM_STACK_FLAGS; + mpnt->vm_ops = NULL; + mpnt->vm_pgoff = 0; + mpnt->vm_file = NULL; + mpnt->vm_private_data = 0; + insert_vm_struct(current->mm, mpnt); + current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; + } + + for (i = 0 ; i < MAX_ARG_PAGES ; i++) { + if (bprm->page[i]) { + current->mm->rss++; + put_dirty_page(current,bprm->page[i],stack_base); + } + stack_base += PAGE_SIZE; + } + + return 0; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.3.42/linux/arch/ia64/ia32/ia32_entry.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/ia32/ia32_entry.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,255 @@ +#include +#include + + .global ia32_ret_from_syscall + .proc ia64_ret_from_syscall +ia32_ret_from_syscall: + cmp.ge p6,p7=r8,r0 // syscall executed successfully? + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 + ;; + st8 [r2]=r8 // store return value in slot for r8 + br.cond.sptk.few ia64_leave_kernel + + // + // Invoke a system call, but do some tracing before and after the call. + // We MUST preserve the current register frame throughout this routine + // because some system calls (such as ia64_execve) directly + // manipulate ar.pfs. + // + // Input: + // r15 = syscall number + // b6 = syscall entry point + // + .global ia32_trace_syscall + .proc ia32_trace_syscall +ia32_trace_syscall: + br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args +.Lret4: br.call.sptk.few rp=b6 // do the syscall +.Lret5: cmp.lt p6,p0=r8,r0 // syscall failed? + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 + ;; + st8.spill [r2]=r8 // store return value in slot for r8 + br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value +.Lret6: br.cond.sptk.many ia64_leave_kernel // rp MUST be != ia64_leave_kernel! + + .endp ia32_trace_syscall + + .align 16 + .global sys32_fork + .proc sys32_fork +sys32_fork: + alloc r16=ar.pfs,2,2,3,0;; + movl r28=1f + mov loc1=rp + br.cond.sptk.many save_switch_stack +1: + mov loc0=r16 // save ar.pfs across do_fork + adds out2=IA64_SWITCH_STACK_SIZE+16,sp + adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp + mov out0=SIGCHLD // out0 = clone_flags + ;; + ld8 out1=[r2] // fetch usp from pt_regs.r12 + br.call.sptk.few rp=do_fork +.ret1: + mov ar.pfs=loc0 + adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack + mov rp=loc1 + ;; + br.ret.sptk.many rp + .endp sys32_fork + + .rodata + .align 8 + .globl ia32_syscall_table +ia32_syscall_table: + data8 sys_ni_syscall /* 0 - old "setup(" system call*/ + data8 sys_exit + data8 sys32_fork + data8 sys_read + data8 sys_write + data8 sys_open /* 5 */ + data8 sys_close + data8 sys32_waitpid + data8 sys_creat + data8 sys_link + data8 sys_unlink /* 10 */ + data8 sys32_execve + data8 sys_chdir + data8 sys_ni_syscall /* sys_time is not supported on ia64 */ + data8 sys_mknod + data8 sys_chmod /* 15 */ + data8 sys_lchown + data8 sys_ni_syscall /* old break syscall holder */ + data8 sys_ni_syscall + data8 sys_lseek + data8 sys_getpid /* 20 */ + data8 sys_mount + data8 sys_oldumount + data8 sys_setuid + data8 sys_getuid + data8 sys_ni_syscall /* sys_stime is not supported on IA64 */ /* 25 */ + data8 sys_ptrace + data8 sys32_alarm + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 30 */ + data8 sys_ni_syscall /* old stty syscall holder */ + data8 sys_ni_syscall /* old gtty syscall holder */ + data8 sys_access + data8 sys_nice + data8 sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + data8 sys_sync + data8 sys_kill + data8 sys_rename + data8 sys_mkdir + data8 sys_rmdir /* 40 */ + data8 sys_dup + data8 sys32_pipe + data8 sys_times + data8 sys_ni_syscall /* old prof syscall holder */ + data8 sys_brk /* 45 */ + data8 sys_setgid + data8 sys_getgid + data8 sys_ni_syscall + data8 sys_geteuid + data8 sys_getegid /* 50 */ + data8 sys_acct + data8 sys_umount /* recycled never used phys( */ + data8 sys_ni_syscall /* old lock syscall holder */ + data8 sys_ioctl + data8 sys_fcntl /* 55 */ + data8 sys_ni_syscall /* old mpx syscall holder */ + data8 sys_setpgid + data8 sys_ni_syscall /* old ulimit syscall holder */ + data8 sys_ni_syscall + data8 sys_umask /* 60 */ + data8 sys_chroot + data8 sys_ustat + data8 sys_dup2 + data8 sys_getppid + data8 sys_getpgrp /* 65 */ + data8 sys_setsid + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_setreuid /* 70 */ + data8 sys_setregid + data8 sys_ni_syscall + data8 sys_sigpending + data8 sys_sethostname + data8 sys32_setrlimit /* 75 */ + data8 sys32_getrlimit + data8 sys_getrusage + data8 sys32_gettimeofday + data8 sys32_settimeofday + data8 sys_getgroups /* 80 */ + data8 sys_setgroups + data8 sys_ni_syscall + data8 sys_symlink + data8 sys_ni_syscall + data8 sys_readlink /* 85 */ + data8 sys_uselib + data8 sys_swapon + data8 sys_reboot + data8 sys32_readdir + data8 sys32_mmap /* 90 */ + data8 sys_munmap + data8 sys_truncate + data8 sys_ftruncate + data8 sys_fchmod + data8 sys_fchown /* 95 */ + data8 sys_getpriority + data8 sys_setpriority + data8 sys_ni_syscall /* old profil syscall holder */ + data8 sys32_statfs + data8 sys32_fstatfs /* 100 */ + data8 sys_ioperm + data8 sys32_socketcall + data8 sys_syslog + data8 sys32_setitimer + data8 sys32_getitimer /* 105 */ + data8 sys32_newstat + data8 sys32_newlstat + data8 sys32_newfstat + data8 sys_ni_syscall + data8 sys_iopl /* 110 */ + data8 sys_vhangup + data8 sys_ni_syscall // used to be sys_idle + data8 sys_ni_syscall + data8 sys32_wait4 + data8 sys_swapoff /* 115 */ + data8 sys_sysinfo + data8 sys32_ipc + data8 sys_fsync + data8 sys32_sigreturn + data8 sys_clone /* 120 */ + data8 sys_setdomainname + data8 sys_newuname + data8 sys_modify_ldt + data8 sys_adjtimex + data8 sys32_mprotect /* 125 */ + data8 sys_sigprocmask + data8 sys_create_module + data8 sys_init_module + data8 sys_delete_module + data8 sys_get_kernel_syms /* 130 */ + data8 sys_quotactl + data8 sys_getpgid + data8 sys_fchdir + data8 sys_bdflush + data8 sys_sysfs /* 135 */ + data8 sys_personality + data8 sys_ni_syscall /* for afs_syscall */ + data8 sys_setfsuid + data8 sys_setfsgid + data8 sys_llseek /* 140 */ + data8 sys32_getdents + data8 sys32_select + data8 sys_flock + data8 sys_msync + data8 sys32_readv /* 145 */ + data8 sys32_writev + data8 sys_getsid + data8 sys_fdatasync + data8 sys_sysctl + data8 sys_mlock /* 150 */ + data8 sys_munlock + data8 sys_mlockall + data8 sys_munlockall + data8 sys_sched_setparam + data8 sys_sched_getparam /* 155 */ + data8 sys_sched_setscheduler + data8 sys_sched_getscheduler + data8 sys_sched_yield + data8 sys_sched_get_priority_max + data8 sys_sched_get_priority_min /* 160 */ + data8 sys_sched_rr_get_interval + data8 sys32_nanosleep + data8 sys_mremap + data8 sys_setresuid + data8 sys_getresuid /* 165 */ + data8 sys_vm86 + data8 sys_query_module + data8 sys_poll + data8 sys_nfsservctl + data8 sys_setresgid /* 170 */ + data8 sys_getresgid + data8 sys_prctl + data8 sys32_rt_sigreturn + data8 sys32_rt_sigaction + data8 sys32_rt_sigprocmask /* 175 */ + data8 sys_rt_sigpending + data8 sys_rt_sigtimedwait + data8 sys_rt_sigqueueinfo + data8 sys_rt_sigsuspend + data8 sys_pread /* 180 */ + data8 sys_pwrite + data8 sys_chown + data8 sys_getcwd + data8 sys_capget + data8 sys_capset /* 185 */ + data8 sys_sigaltstack + data8 sys_sendfile + data8 sys_ni_syscall /* streams1 */ + data8 sys_ni_syscall /* streams2 */ + data8 sys32_vfork /* 190 */ diff -u --recursive --new-file v2.3.42/linux/arch/ia64/ia32/ia32_signal.c linux/arch/ia64/ia32/ia32_signal.c --- v2.3.42/linux/arch/ia64/ia32/ia32_signal.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/ia32/ia32_signal.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,412 @@ +/* + * IA32 Architecture-specific signal handling support. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999 Arun Sharma + * Copyright (C) 2000 VA Linux Co + * Copyright (C) 2000 Don Dugger + * + * Derived from i386 and Alpha versions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define DEBUG_SIG 0 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + + +struct sigframe_ia32 +{ + int pretcode; + int sig; + struct sigcontext_ia32 sc; + struct _fpstate_ia32 fpstate; + unsigned int extramask[_IA32_NSIG_WORDS-1]; + char retcode[8]; +}; + +struct rt_sigframe_ia32 +{ + int pretcode; + int sig; + int pinfo; + int puc; + struct siginfo info; + struct ucontext_ia32 uc; + struct _fpstate_ia32 fpstate; + char retcode[8]; +}; + +static int +setup_sigcontext_ia32(struct sigcontext_ia32 *sc, struct _fpstate_ia32 *fpstate, + struct pt_regs *regs, unsigned long mask) +{ + int err = 0; + + err |= __put_user((regs->r16 >> 32) & 0xffff , (unsigned int *)&sc->fs); + err |= __put_user((regs->r16 >> 48) & 0xffff , (unsigned int *)&sc->gs); + + err |= __put_user((regs->r16 >> 56) & 0xffff, (unsigned int *)&sc->es); + err |= __put_user(regs->r16 & 0xffff, (unsigned int *)&sc->ds); + err |= __put_user(regs->r15, &sc->edi); + err |= __put_user(regs->r14, &sc->esi); + err |= __put_user(regs->r13, &sc->ebp); + err |= __put_user(regs->r12, &sc->esp); + err |= __put_user(regs->r11, &sc->ebx); + err |= __put_user(regs->r10, &sc->edx); + err |= __put_user(regs->r9, &sc->ecx); + err |= __put_user(regs->r8, &sc->eax); +#if 0 + err |= __put_user(current->tss.trap_no, &sc->trapno); + err |= __put_user(current->tss.error_code, &sc->err); +#endif + err |= __put_user(regs->cr_iip, &sc->eip); + err |= __put_user(regs->r17 & 0xffff, (unsigned int *)&sc->cs); +#if 0 + err |= __put_user(regs->eflags, &sc->eflags); +#endif + + err |= __put_user(regs->r12, &sc->esp_at_signal); + err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss); + +#if 0 + tmp = save_i387(fpstate); + if (tmp < 0) + err = 1; + else + err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); + + /* non-iBCS2 extensions.. */ + err |= __put_user(mask, &sc->oldmask); + err |= __put_user(current->tss.cr2, &sc->cr2); +#endif + + return err; +} + +static int +restore_sigcontext_ia32(struct pt_regs *regs, struct sigcontext_ia32 *sc, int *peax) +{ + unsigned int err = 0; + +#define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) + +#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) tmp << 48) +#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) tmp << 32) +#define copyseg_cs(tmp) (regs->r17 |= tmp) +#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) tmp << 16) +#define copyseg_es(tmp) (regs->r16 |= (unsigned long) tmp << 16) +#define copyseg_ds(tmp) (regs->r16 |= tmp) + +#define COPY_SEG(seg) \ + { unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + copyseg_##seg(tmp); } + +#define COPY_SEG_STRICT(seg) \ + { unsigned short tmp; \ + err |= __get_user(tmp, &sc->seg); \ + copyseg_##seg(tmp|3); } + + /* To make COPY_SEGs easier, we zero r16, r17 */ + regs->r16 = 0; + regs->r17 = 0; + + COPY_SEG(gs); + COPY_SEG(fs); + COPY_SEG(es); + COPY_SEG(ds); + COPY(r15, edi); + COPY(r14, esi); + COPY(r13, ebp); + COPY(r12, esp); + COPY(r11, ebx); + COPY(r10, edx); + COPY(r9, ecx); + COPY(cr_iip, eip); + COPY_SEG_STRICT(cs); + COPY_SEG_STRICT(ss); +#if 0 + { + unsigned int tmpflags; + err |= __get_user(tmpflags, &sc->eflags); + /* XXX: Change this to ar.eflags */ + regs->eflags = (regs->eflags & ~0x40DD5) | (tmpflags & 0x40DD5); + regs->orig_eax = -1; /* disable syscall checks */ + } + + { + struct _fpstate * buf; + err |= __get_user(buf, &sc->fpstate); + if (buf) { + if (verify_area(VERIFY_READ, buf, sizeof(*buf))) + goto badframe; + err |= restore_i387(buf); + } + } +#endif + + err |= __get_user(*peax, &sc->eax); + return err; + +#if 0 +badframe: + return 1; +#endif + +} + +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) +{ + unsigned long esp; + unsigned int xss; + + /* Default to using normal stack */ + esp = regs->r12; + xss = regs->r16 >> 16; + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (! on_sig_stack(esp)) + esp = current->sas_ss_sp + current->sas_ss_size; + } + /* Legacy stack switching not supported */ + + return (void *)((esp - frame_size) & -8ul); +} + +static void +setup_frame_ia32(int sig, struct k_sigaction *ka, sigset_t *set, + struct pt_regs * regs) +{ + struct sigframe_ia32 *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? (int)(current->exec_domain->signal_invmap[sig]) + : sig), + &frame->sig); + + err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); + + if (_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + err |= __put_user(frame->retcode, &frame->pretcode); + /* This is popl %eax ; movl $,%eax ; int $0x80 */ + err |= __put_user(0xb858, (short *)(frame->retcode+0)); +#define __IA32_NR_sigreturn 119 + err |= __put_user(__IA32_NR_sigreturn & 0xffff, (short *)(frame->retcode+2)); + err |= __put_user(__IA32_NR_sigreturn >> 16, (short *)(frame->retcode+4)); + err |= __put_user(0x80cd, (short *)(frame->retcode+6)); + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->r12 = (unsigned long) frame; + regs->cr_iip = (unsigned long) ka->sa.sa_handler; + + set_fs(USER_DS); + regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; + +#if 0 + regs->eflags &= ~TF_MASK; +#endif + +#if 1 + printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", + current->comm, current->pid, frame, regs->cr_iip, frame->pretcode); +#endif + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static void +setup_rt_frame_ia32(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs * regs) +{ + struct rt_sigframe_ia32 *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= __copy_to_user(&frame->info, info, sizeof(*info)); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->r12), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext_ia32(&frame->uc.uc_mcontext, &frame->fpstate, + regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + err |= __put_user(frame->retcode, &frame->pretcode); + /* This is movl $,%eax ; int $0x80 */ + err |= __put_user(0xb8, (char *)(frame->retcode+0)); +#define __IA32_NR_rt_sigreturn 173 + err |= __put_user(__IA32_NR_rt_sigreturn, (int *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short *)(frame->retcode+5)); + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->r12 = (unsigned long) frame; + regs->cr_iip = (unsigned long) ka->sa.sa_handler; + + set_fs(USER_DS); + + regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; + +#if 0 + regs->eflags &= ~TF_MASK; +#endif + +#if 1 + printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%x\n", + current->comm, current->pid, frame, regs->cr_iip, frame->pretcode); +#endif + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +long +ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + /* Set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame_ia32(sig, ka, info, set, regs); + else + setup_frame_ia32(sig, ka, set, regs); + +} + +asmlinkage int +sys32_sigreturn(int arg1, int arg2, int arg3, int arg4, int arg5, unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + struct sigframe_ia32 *frame = (struct sigframe_ia32 *)(regs->r12- 8); + sigset_t set; + int eax; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_IA32_NSIG_WORDS > 1 + && __copy_from_user((((char *) &set.sig) + 4), + &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = (sigset_t) set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext_ia32(regs, &frame->sc, &eax)) + goto badframe; + return eax; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int +sys32_rt_sigreturn(int arg1, int arg2, int arg3, int arg4, int arg5, unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + struct rt_sigframe_ia32 *frame = (struct rt_sigframe_ia32 *)(regs->r12 - 4); + sigset_t set; + stack_t st; + int eax; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext_ia32(regs, &frame->uc.uc_mcontext, &eax)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs->r12); + + return eax; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/ia32/ia32_support.c linux/arch/ia64/ia32/ia32_support.c --- v2.3.42/linux/arch/ia64/ia32/ia32_support.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/ia32/ia32_support.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,61 @@ +/* + * IA32 helper functions + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern unsigned long *ia32_gdt_table, *ia32_tss; + +extern void die_if_kernel (char *str, struct pt_regs *regs, long err); + +/* + * Setup IA32 GDT and TSS + */ +void +ia32_gdt_init(void) +{ + unsigned long gdt_and_tss_page; + + /* allocate two IA-32 pages of memory: */ + gdt_and_tss_page = __get_free_pages(GFP_KERNEL, + (IA32_PAGE_SHIFT < PAGE_SHIFT) + ? 0 : (IA32_PAGE_SHIFT + 1) - PAGE_SHIFT); + ia32_gdt_table = (unsigned long *) gdt_and_tss_page; + ia32_tss = (unsigned long *) (gdt_and_tss_page + IA32_PAGE_SIZE); + + /* Zero the gdt and tss */ + memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE); + + /* CS descriptor in IA-32 format */ + ia32_gdt_table[4] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0xBL, 1L, + 3L, 1L, 1L, 1L, 1L); + + /* DS descriptor in IA-32 format */ + ia32_gdt_table[5] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0x3L, 1L, + 3L, 1L, 1L, 1L, 1L); +} + +/* + * Handle bad IA32 interrupt via syscall + */ +void +ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs) +{ + siginfo_t siginfo; + + die_if_kernel("Bad IA-32 interrupt", regs, int_num); + + siginfo.si_signo = SIGTRAP; + siginfo.si_errno = int_num; /* XXX is it legal to abuse si_errno like this? */ + siginfo.si_code = TRAP_BRKPT; + force_sig_info(SIGTRAP, &siginfo, current); +} + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.3.42/linux/arch/ia64/ia32/sys_ia32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/ia32/sys_ia32.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,4309 @@ +/* + * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on + * sys_sparc32 + * + * Copyright (C) 2000 VA Linux Co + * Copyright (C) 2000 Don Dugger + * Copyright (C) 1999 Arun Sharma + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * + * These routines maintain argument size conversion between 32bit and 64bit + * environment. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define A(__x) ((unsigned long)(__x)) +#define AA(__x) ((unsigned long)(__x)) + +/* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys32_vfork( +int dummy0, +int dummy1, +int dummy2, +int dummy3, +int dummy4, +int dummy5, +int dummy6, +int dummy7, +int stack) +{ + struct pt_regs *regs = (struct pt_regs *)&stack; + + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r12, regs); +} + +static int +nargs(unsigned int arg, char **ap) +{ + char *ptr; + int n, err; + + n = 0; + do { + if (err = get_user(ptr, (int *)arg)) + return(err); + if (ap) + *ap++ = ptr; + arg += sizeof(unsigned int); + n++; + } while (ptr); + return(n - 1); +} + +asmlinkage long +sys32_execve( +char *filename, +unsigned int argv, +unsigned int envp, +int dummy3, +int dummy4, +int dummy5, +int dummy6, +int dummy7, +int stack) +{ + struct pt_regs *regs = (struct pt_regs *)&stack; + char **av, **ae; + int na, ne, r, len; + + na = nargs(argv, NULL); + ne = nargs(envp, NULL); + len = (na + ne + 2) * sizeof(*av); + /* + * kmalloc won't work because the `sys_exec' code will attempt + * to do a `get_user' on the arg list and `get_user' will fail + * on a kernel address (simplifies `get_user'). Instead we + * do an mmap to get a user address. Note that since a successful + * `execve' frees all current memory we only have to do an + * `munmap' if the `execve' failes. + */ + down(¤t->mm->mmap_sem); + lock_kernel(); + + av = do_mmap_pgoff(0, NULL, len, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0); + + unlock_kernel(); + up(¤t->mm->mmap_sem); + + if (IS_ERR(av)) + return(av); + ae = av + na + 1; + av[na] = (char *)0; + ae[ne] = (char *)0; + (void)nargs(argv, av); + (void)nargs(envp, ae); + r = sys_execve(filename, av, ae, regs); + if (IS_ERR(r)) + sys_munmap(av, len); + return(r); +} + +static inline int +putstat(struct stat32 *ubuf, struct stat *kbuf) +{ + int err; + + err = put_user (kbuf->st_dev, &ubuf->st_dev); + err |= __put_user (kbuf->st_ino, &ubuf->st_ino); + err |= __put_user (kbuf->st_mode, &ubuf->st_mode); + err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink); + err |= __put_user (kbuf->st_uid, &ubuf->st_uid); + err |= __put_user (kbuf->st_gid, &ubuf->st_gid); + err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev); + err |= __put_user (kbuf->st_size, &ubuf->st_size); + err |= __put_user (kbuf->st_atime, &ubuf->st_atime); + err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime); + err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime); + err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize); + err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks); + return err; +} + +extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf); + +asmlinkage int +sys32_newstat(char * filename, struct stat32 *statbuf) +{ + int ret; + struct stat s; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_newstat(filename, &s); + set_fs (old_fs); + if (putstat (statbuf, &s)) + return -EFAULT; + return ret; +} + +extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf); + +asmlinkage int +sys32_newlstat(char * filename, struct stat32 *statbuf) +{ + int ret; + struct stat s; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_newlstat(filename, &s); + set_fs (old_fs); + if (putstat (statbuf, &s)) + return -EFAULT; + return ret; +} + +extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); + +asmlinkage int +sys32_newfstat(unsigned int fd, struct stat32 *statbuf) +{ + int ret; + struct stat s; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_newfstat(fd, &s); + set_fs (old_fs); + if (putstat (statbuf, &s)) + return -EFAULT; + return ret; +} + +#define ALIGN4K(a) (((a) + 0xfff) & ~0xfff) +#define OFFSET4K(a) ((a) & 0xfff) + +unsigned long +do_mmap_fake(struct file *file, unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long off) +{ + struct inode *inode; + void *front, *back; + unsigned long baddr; + int r; + char c; + + if (OFFSET4K(addr) || OFFSET4K(off)) + return -EINVAL; + if (prot & PROT_WRITE) + prot |= PROT_EXEC; + front = NULL; + back = NULL; + if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) { + front = kmalloc(addr - baddr, GFP_KERNEL); + memcpy(front, (void *)baddr, addr - baddr); + } + if ((addr + len) & ~PAGE_MASK && get_user(c, (char *)(addr + len)) == 0) { + back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); + memcpy(back, addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); + } + if ((r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0)) < 0) + return(r); + if (back) { + memcpy(addr + len, back, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); + kfree(back); + } + if (front) { + memcpy((void *)baddr, front, addr - baddr); + kfree(front); + } + if (flags & MAP_ANONYMOUS) { + memset(addr, 0, len); + return(addr); + } + if (!file) + return -EINVAL; + inode = file->f_dentry->d_inode; + if (!inode->i_op || !inode->i_op->default_file_ops) + return -EINVAL; + if (!file->f_op->read) + return -EINVAL; + if (file->f_op->llseek) { + if (file->f_op->llseek(file,off,0) != off) + return -EINVAL; + } else + file->f_pos = off; + r = file->f_op->read(file, (char *)addr, len, &file->f_pos); + return (r < 0) ? -EINVAL : addr; +} + +/* + * Linux/i386 didn't use to be able to handle more than + * 4 system call parameters, so these system calls used a memory + * block for parameter passing.. + */ + +struct mmap_arg_struct { + unsigned int addr; + unsigned int len; + unsigned int prot; + unsigned int flags; + unsigned int fd; + unsigned int offset; +}; + +asmlinkage int +sys32_mmap(struct mmap_arg_struct *arg) +{ + int error = -EFAULT; + struct file * file = NULL; + struct mmap_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + + down(¤t->mm->mmap_sem); + lock_kernel(); + if (!(a.flags & MAP_ANONYMOUS)) { + error = -EBADF; + file = fget(a.fd); + if (!file) + goto out; + } + a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + if ((a.flags & MAP_FIXED) && ((a.addr & ~PAGE_MASK) || (a.offset & ~PAGE_MASK))) { + unlock_kernel(); + up(¤t->mm->mmap_sem); + error = do_mmap_fake(file, a.addr, a.len, a.prot, a.flags, a.offset); + down(¤t->mm->mmap_sem); + lock_kernel(); + } else + error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); + if (file) + fput(file); +out: + unlock_kernel(); + up(¤t->mm->mmap_sem); + return error; +} + +asmlinkage long +sys32_pipe(int *fd) +{ + int retval; + int fds[2]; + + lock_kernel(); + retval = do_pipe(fds); + if (retval) + goto out; + if (copy_to_user(fd, fds, sizeof(fds))) + retval = -EFAULT; + out: + unlock_kernel(); + return retval; +} + +asmlinkage long +sys32_mprotect(unsigned long start, size_t len, unsigned long prot) +{ + + if (prot == 0) + return(0); + len += start & ~PAGE_MASK; + if ((start & ~PAGE_MASK) && (prot & PROT_WRITE)) + prot |= PROT_EXEC; + return(sys_mprotect(start & PAGE_MASK, len & PAGE_MASK, prot)); +} + +asmlinkage int +sys32_rt_sigaction(int sig, struct sigaction32 *act, + struct sigaction32 *oact, unsigned int sigsetsize) +{ + struct k_sigaction new_ka, old_ka; + int ret; + sigset32_t set32; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset32_t)) + return -EINVAL; + + if (act) { + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); + ret |= __copy_from_user(&set32, &act->sa_mask, + sizeof(sigset32_t)); + switch (_NSIG_WORDS) { + case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] + | (((long)set32.sig[7]) << 32); + case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] + | (((long)set32.sig[5]) << 32); + case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] + | (((long)set32.sig[3]) << 32); + case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] + | (((long)set32.sig[1]) << 32); + } + ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + + if (ret) + return -EFAULT; + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + switch (_NSIG_WORDS) { + case 4: + set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); + set32.sig[6] = old_ka.sa.sa_mask.sig[3]; + case 3: + set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); + set32.sig[4] = old_ka.sa.sa_mask.sig[2]; + case 2: + set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); + set32.sig[2] = old_ka.sa.sa_mask.sig[1]; + case 1: + set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); + set32.sig[0] = old_ka.sa.sa_mask.sig[0]; + } + ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); + ret |= __copy_to_user(&oact->sa_mask, &set32, + sizeof(sigset32_t)); + ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + } + + return ret; +} + + +extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, + size_t sigsetsize); + +asmlinkage int +sys32_rt_sigprocmask(int how, sigset32_t *set, sigset32_t *oset, + unsigned int sigsetsize) +{ + sigset_t s; + sigset32_t s32; + int ret; + mm_segment_t old_fs = get_fs(); + + if (set) { + if (copy_from_user (&s32, set, sizeof(sigset32_t))) + return -EFAULT; + switch (_NSIG_WORDS) { + case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); + case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); + case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); + case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + } + } + set_fs (KERNEL_DS); + ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, + sigsetsize); + set_fs (old_fs); + if (ret) return ret; + if (oset) { + switch (_NSIG_WORDS) { + case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; + case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; + case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; + case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; + } + if (copy_to_user (oset, &s32, sizeof(sigset32_t))) + return -EFAULT; + } + return 0; +} + +static inline int +put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) +{ + int err; + + err = put_user (kbuf->f_type, &ubuf->f_type); + err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize); + err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks); + err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree); + err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail); + err |= __put_user (kbuf->f_files, &ubuf->f_files); + err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree); + err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen); + err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]); + err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]); + return err; +} + +extern asmlinkage int sys_statfs(const char * path, struct statfs * buf); + +asmlinkage int +sys32_statfs(const char * path, struct statfs32 *buf) +{ + int ret; + struct statfs s; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_statfs((const char *)path, &s); + set_fs (old_fs); + if (put_statfs(buf, &s)) + return -EFAULT; + return ret; +} + +extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf); + +asmlinkage int +sys32_fstatfs(unsigned int fd, struct statfs32 *buf) +{ + int ret; + struct statfs s; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_fstatfs(fd, &s); + set_fs (old_fs); + if (put_statfs(buf, &s)) + return -EFAULT; + return ret; +} + +struct timeval32 +{ + int tv_sec, tv_usec; +}; + +struct itimerval32 +{ + struct timeval32 it_interval; + struct timeval32 it_value; +}; + +static inline long +get_tv32(struct timeval *o, struct timeval32 *i) +{ + 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 +put_tv32(struct timeval32 *o, struct timeval *i) +{ + return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || + (__put_user(i->tv_sec, &o->tv_sec) | + __put_user(i->tv_usec, &o->tv_usec))); +} + +static inline long +get_it32(struct itimerval *o, struct itimerval32 *i) +{ + return (!access_ok(VERIFY_READ, i, sizeof(*i)) || + (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | + __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 +put_it32(struct itimerval32 *o, struct itimerval *i) +{ + return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) || + (__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); + +asmlinkage int +sys32_getitimer(int which, struct itimerval32 *it) +{ + struct itimerval kit; + int error; + + error = do_getitimer(which, &kit); + if (!error && put_it32(it, &kit)) + error = -EFAULT; + + return error; +} + +extern int do_setitimer(int which, struct itimerval *, struct itimerval *); + +asmlinkage int +sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out) +{ + struct itimerval kin, kout; + int error; + + if (in) { + if (get_it32(&kin, in)) + return -EFAULT; + } else + memset(&kin, 0, sizeof(kin)); + + error = do_setitimer(which, &kin, out ? &kout : NULL); + if (error || !out) + return error; + if (put_it32(out, &kout)) + return -EFAULT; + + return 0; + +} +asmlinkage unsigned long +sys32_alarm(unsigned int seconds) +{ + struct itimerval it_new, it_old; + unsigned int oldalarm; + + it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0; + it_new.it_value.tv_sec = seconds; + it_new.it_value.tv_usec = 0; + do_setitimer(ITIMER_REAL, &it_new, &it_old); + oldalarm = it_old.it_value.tv_sec; + /* ehhh.. We can't return 0 if we have an alarm pending.. */ + /* And we'd better return too much than too little anyway */ + if (it_old.it_value.tv_usec) + oldalarm++; + return oldalarm; +} + +/* Translations due to time_t size differences. Which affects all + sorts of things, like timeval and itimerval. */ + +extern struct timezone sys_tz; +extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); + +asmlinkage int +sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz) +{ + if (tv) { + struct timeval ktv; + do_gettimeofday(&ktv); + if (put_tv32(tv, &ktv)) + return -EFAULT; + } + if (tz) { + if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) + return -EFAULT; + } + return 0; +} + +asmlinkage int +sys32_settimeofday(struct timeval32 *tv, struct timezone *tz) +{ + struct timeval ktv; + struct timezone ktz; + + if (tv) { + if (get_tv32(&ktv, tv)) + return -EFAULT; + } + if (tz) { + if (copy_from_user(&ktz, tz, sizeof(ktz))) + return -EFAULT; + } + + return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL); +} + +struct dirent32 { + unsigned int d_ino; + unsigned int d_off; + unsigned short d_reclen; + char d_name[NAME_MAX + 1]; +}; + +static void +xlate_dirent(void *dirent, long n) +{ + long off; + struct dirent *dirp; + struct dirent32 *dirp32; + + off = 0; + while (off < n) { + dirp = (struct dirent *)(dirent + off); + off += dirp->d_reclen; + dirp32 = (struct dirent32 *)dirp; + dirp32->d_ino = dirp->d_ino; + dirp32->d_off = (unsigned int)dirp->d_off; + dirp32->d_reclen = dirp->d_reclen; + strncpy(dirp32->d_name, dirp->d_name, dirp->d_reclen - ((3 * 4) + 2)); + } + return; +} + +asmlinkage long +sys32_getdents(unsigned int fd, void * dirent, unsigned int count) +{ + long n; + + if ((n = sys_getdents(fd, dirent, count)) < 0) + return(n); + xlate_dirent(dirent, n); + return(n); +} + +asmlinkage int +sys32_readdir(unsigned int fd, void * dirent, unsigned int count) +{ + int n; + struct dirent *dirp; + + if ((n = old_readdir(fd, dirent, count)) < 0) + return(n); + dirp = (struct dirent *)dirent; + xlate_dirent(dirent, dirp->d_reclen); + return(n); +} + +/* + * We can actually return ERESTARTSYS instead of EINTR, but I'd + * like to be certain this leads to no problems. So I return + * EINTR just for safety. + * + * Update: ERESTARTSYS breaks at least the xview clock binary, so + * I'm trying ERESTARTNOHAND which restart only when you want to. + */ +#define MAX_SELECT_SECONDS \ + ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) +#define ROUND_UP(x,y) (((x)+(y)-1)/(y)) + +asmlinkage int +sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32) +{ + fd_set_bits fds; + char *bits; + long timeout; + int ret, size; + + timeout = MAX_SCHEDULE_TIMEOUT; + if (tvp32) { + time_t sec, usec; + + get_user(sec, &tvp32->tv_sec); + get_user(usec, &tvp32->tv_usec); + + ret = -EINVAL; + if (sec < 0 || usec < 0) + goto out_nofds; + + if ((unsigned long) sec < MAX_SELECT_SECONDS) { + timeout = ROUND_UP(usec, 1000000/HZ); + timeout += sec * (unsigned long) HZ; + } + } + + ret = -EINVAL; + if (n < 0) + goto out_nofds; + + if (n > current->files->max_fdset) + n = current->files->max_fdset; + + /* + * We need 6 bitmaps (in/out/ex for both incoming and outgoing), + * since we used fdset we need to allocate memory in units of + * long-words. + */ + ret = -ENOMEM; + size = FDS_BYTES(n); + bits = kmalloc(6 * size, GFP_KERNEL); + if (!bits) + goto out_nofds; + fds.in = (unsigned long *) bits; + fds.out = (unsigned long *) (bits + size); + fds.ex = (unsigned long *) (bits + 2*size); + fds.res_in = (unsigned long *) (bits + 3*size); + fds.res_out = (unsigned long *) (bits + 4*size); + fds.res_ex = (unsigned long *) (bits + 5*size); + + if ((ret = get_fd_set(n, inp, fds.in)) || + (ret = get_fd_set(n, outp, fds.out)) || + (ret = get_fd_set(n, exp, fds.ex))) + goto out; + zero_fd_set(n, fds.res_in); + zero_fd_set(n, fds.res_out); + zero_fd_set(n, fds.res_ex); + + ret = do_select(n, &fds, &timeout); + + if (tvp32 && !(current->personality & STICKY_TIMEOUTS)) { + time_t sec = 0, usec = 0; + if (timeout) { + sec = timeout / HZ; + usec = timeout % HZ; + usec *= (1000000/HZ); + } + put_user(sec, (int *)&tvp32->tv_sec); + put_user(usec, (int *)&tvp32->tv_usec); + } + + if (ret < 0) + goto out; + if (!ret) { + ret = -ERESTARTNOHAND; + if (signal_pending(current)) + goto out; + ret = 0; + } + + set_fd_set(n, inp, fds.res_in); + set_fd_set(n, outp, fds.res_out); + set_fd_set(n, exp, fds.res_ex); + +out: + kfree(bits); +out_nofds: + return ret; +} + +struct rusage32 { + struct timeval32 ru_utime; + struct timeval32 ru_stime; + int ru_maxrss; + int ru_ixrss; + int ru_idrss; + int ru_isrss; + int ru_minflt; + int ru_majflt; + int ru_nswap; + int ru_inblock; + int ru_oublock; + int ru_msgsnd; + int ru_msgrcv; + int ru_nsignals; + int ru_nvcsw; + int ru_nivcsw; +}; + +static int +put_rusage (struct rusage32 *ru, struct rusage *r) +{ + int err; + + err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); + err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); + err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); + err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); + err |= __put_user (r->ru_maxrss, &ru->ru_maxrss); + err |= __put_user (r->ru_ixrss, &ru->ru_ixrss); + err |= __put_user (r->ru_idrss, &ru->ru_idrss); + err |= __put_user (r->ru_isrss, &ru->ru_isrss); + err |= __put_user (r->ru_minflt, &ru->ru_minflt); + err |= __put_user (r->ru_majflt, &ru->ru_majflt); + err |= __put_user (r->ru_nswap, &ru->ru_nswap); + err |= __put_user (r->ru_inblock, &ru->ru_inblock); + err |= __put_user (r->ru_oublock, &ru->ru_oublock); + err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd); + err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv); + err |= __put_user (r->ru_nsignals, &ru->ru_nsignals); + err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw); + err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw); + return err; +} + +extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, + int options, struct rusage * ru); + +asmlinkage int +sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, + struct rusage32 *ru) +{ + if (!ru) + return sys_wait4(pid, stat_addr, options, NULL); + else { + struct rusage r; + int ret; + unsigned int status; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); + set_fs (old_fs); + if (put_rusage (ru, &r)) return -EFAULT; + if (stat_addr && put_user (status, stat_addr)) + return -EFAULT; + return ret; + } +} + +asmlinkage int +sys32_waitpid(__kernel_pid_t32 pid, unsigned int *stat_addr, int options) +{ + return sys32_wait4(pid, stat_addr, options, NULL); +} + +struct timespec32 { + int tv_sec; + int tv_nsec; +}; + +extern asmlinkage int sys_nanosleep(struct timespec *rqtp, + struct timespec *rmtp); + +asmlinkage int +sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) +{ + struct timespec t; + int ret; + mm_segment_t old_fs = get_fs (); + + if (get_user (t.tv_sec, &rqtp->tv_sec) || + __get_user (t.tv_nsec, &rqtp->tv_nsec)) + return -EFAULT; + set_fs (KERNEL_DS); + ret = sys_nanosleep(&t, rmtp ? &t : NULL); + set_fs (old_fs); + if (rmtp && ret == -EINTR) { + if (__put_user (t.tv_sec, &rmtp->tv_sec) || + __put_user (t.tv_nsec, &rmtp->tv_nsec)) + return -EFAULT; + } + return ret; +} + +struct iovec32 { unsigned int iov_base; int iov_len; }; + +typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *); + +static long +do_readv_writev32(int type, struct file *file, const struct iovec32 *vector, + u32 count) +{ + unsigned long tot_len; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov=iovstack, *ivp; + struct inode *inode; + long retval, i; + IO_fn_t fn; + + /* First get the "struct iovec" from user memory and + * verify all the pointers + */ + if (!count) + return 0; + if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count)) + return -EFAULT; + if (count > UIO_MAXIOV) + return -EINVAL; + if (count > UIO_FASTIOV) { + iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); + if (!iov) + return -ENOMEM; + } + + tot_len = 0; + i = count; + ivp = iov; + while(i > 0) { + u32 len; + u32 buf; + + __get_user(len, &vector->iov_len); + __get_user(buf, &vector->iov_base); + tot_len += len; + ivp->iov_base = (void *)A(buf); + ivp->iov_len = (__kernel_size_t) len; + vector++; + ivp++; + i--; + } + + inode = file->f_dentry->d_inode; + /* VERIFY_WRITE actually means a read, as we write to user space */ + retval = locks_verify_area((type == VERIFY_WRITE + ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE), + inode, file, file->f_pos, tot_len); + if (retval) { + if (iov != iovstack) + kfree(iov); + return retval; + } + + /* Then do the actual IO. Note that sockets need to be handled + * specially as they have atomicity guarantees and can handle + * iovec's natively + */ + if (inode->i_sock) { + int err; + err = sock_readv_writev(type, inode, file, iov, count, tot_len); + if (iov != iovstack) + kfree(iov); + return err; + } + + if (!file->f_op) { + if (iov != iovstack) + kfree(iov); + return -EINVAL; + } + /* VERIFY_WRITE actually means a read, as we write to user space */ + fn = file->f_op->read; + if (type == VERIFY_READ) + fn = (IO_fn_t) file->f_op->write; + ivp = iov; + while (count > 0) { + void * base; + int len, nr; + + base = ivp->iov_base; + len = ivp->iov_len; + ivp++; + count--; + nr = fn(file, base, len, &file->f_pos); + if (nr < 0) { + if (retval) + break; + retval = nr; + break; + } + retval += nr; + if (nr != len) + break; + } + if (iov != iovstack) + kfree(iov); + return retval; +} + +asmlinkage long +sys32_readv(int fd, struct iovec32 *vector, u32 count) +{ + struct file *file; + long ret = -EBADF; + + lock_kernel(); + file = fget(fd); + if(!file) + goto bad_file; + + if(!(file->f_mode & 1)) + goto out; + + ret = do_readv_writev32(VERIFY_WRITE, file, + vector, count); +out: + fput(file); +bad_file: + unlock_kernel(); + return ret; +} + +asmlinkage long +sys32_writev(int fd, struct iovec32 *vector, u32 count) +{ + struct file *file; + int ret = -EBADF; + + lock_kernel(); + file = fget(fd); + if(!file) + goto bad_file; + + if(!(file->f_mode & 2)) + goto out; + + down(&file->f_dentry->d_inode->i_sem); + ret = do_readv_writev32(VERIFY_READ, file, + vector, count); + up(&file->f_dentry->d_inode->i_sem); +out: + fput(file); +bad_file: + unlock_kernel(); + return ret; +} + +#define RLIM_INFINITY32 0x7fffffff +#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) + +struct rlimit32 { + int rlim_cur; + int rlim_max; +}; + +extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim); + +asmlinkage int +sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim) +{ + struct rlimit r; + int ret; + mm_segment_t old_fs = get_fs (); + + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &r); + set_fs (old_fs); + if (!ret) { + ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur); + ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max); + } + return ret; +} + +extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim); + +asmlinkage int +sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim) +{ + struct rlimit r; + int ret; + mm_segment_t old_fs = get_fs (); + + if (resource >= RLIM_NLIMITS) return -EINVAL; + if (get_user (r.rlim_cur, &rlim->rlim_cur) || + __get_user (r.rlim_max, &rlim->rlim_max)) + return -EFAULT; + if (r.rlim_cur == RLIM_INFINITY32) + r.rlim_cur = RLIM_INFINITY; + if (r.rlim_max == RLIM_INFINITY32) + r.rlim_max = RLIM_INFINITY; + set_fs (KERNEL_DS); + ret = sys_setrlimit(resource, &r); + set_fs (old_fs); + return ret; +} + +/* Argument list sizes for sys_socketcall */ +#define AL(x) ((x) * sizeof(u32)) +static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), + AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), + AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; +#undef AL + +extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen); +extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, + int addrlen); +extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, + int *upeer_addrlen); +extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, + int *usockaddr_len); +extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, + int *usockaddr_len); +extern asmlinkage int sys_send(int fd, void *buff, size_t len, unsigned flags); +extern asmlinkage int sys_sendto(int fd, u32 buff, __kernel_size_t32 len, + unsigned flags, u32 addr, int addr_len); +extern asmlinkage int sys_recv(int fd, void *ubuf, size_t size, unsigned flags); +extern asmlinkage int sys_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, + unsigned flags, u32 addr, u32 addr_len); +extern asmlinkage int sys_setsockopt(int fd, int level, int optname, + char *optval, int optlen); +extern asmlinkage int sys_getsockopt(int fd, int level, int optname, + u32 optval, u32 optlen); + +extern asmlinkage int sys_socket(int family, int type, int protocol); +extern asmlinkage int sys_socketpair(int family, int type, int protocol, + int usockvec[2]); +extern asmlinkage int sys_shutdown(int fd, int how); +extern asmlinkage int sys_listen(int fd, int backlog); + +asmlinkage int sys32_socketcall(int call, u32 *args) +{ + int i, ret; + u32 a[6]; + u32 a0,a1; + + if (callSYS_RECVMSG) + return -EINVAL; + if (copy_from_user(a, args, nas[call])) + return -EFAULT; + a0=a[0]; + a1=a[1]; + + switch(call) + { + case SYS_SOCKET: + ret = sys_socket(a0, a1, a[2]); + break; + case SYS_BIND: + ret = sys_bind(a0, (struct sockaddr *)A(a1), a[2]); + break; + case SYS_CONNECT: + ret = sys_connect(a0, (struct sockaddr *)A(a1), a[2]); + break; + case SYS_LISTEN: + ret = sys_listen(a0, a1); + break; + case SYS_ACCEPT: + ret = sys_accept(a0, (struct sockaddr *)A(a1), + (int *)A(a[2])); + break; + case SYS_GETSOCKNAME: + ret = sys_getsockname(a0, (struct sockaddr *)A(a1), + (int *)A(a[2])); + break; + case SYS_GETPEERNAME: + ret = sys_getpeername(a0, (struct sockaddr *)A(a1), + (int *)A(a[2])); + break; + case SYS_SOCKETPAIR: + ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3])); + break; + case SYS_SEND: + ret = sys_send(a0, (void *)A(a1), a[2], a[3]); + break; + case SYS_SENDTO: + ret = sys_sendto(a0, a1, a[2], a[3], a[4], a[5]); + break; + case SYS_RECV: + ret = sys_recv(a0, (void *)A(a1), a[2], a[3]); + break; + case SYS_RECVFROM: + ret = sys_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); + break; + case SYS_SHUTDOWN: + ret = sys_shutdown(a0,a1); + break; + case SYS_SETSOCKOPT: + ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), + a[4]); + break; + case SYS_GETSOCKOPT: + ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]); + break; + case SYS_SENDMSG: + ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1), + a[2]); + break; + case SYS_RECVMSG: + ret = sys32_recvmsg(a0, (struct msghdr32 *)A(a1), + a[2]); + break; + default: + ret = EINVAL; + break; + } + return ret; +} + +/* + * Declare the IA32 version of the msghdr + */ + +struct msghdr32 { + unsigned int msg_name; /* Socket name */ + int msg_namelen; /* Length of name */ + unsigned int msg_iov; /* Data blocks */ + unsigned int msg_iovlen; /* Number of blocks */ + unsigned int msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ + unsigned int msg_controllen; /* Length of cmsg list */ + unsigned msg_flags; +}; + +static inline int +shape_msg(struct msghdr *mp, struct msghdr32 *mp32) +{ + unsigned int i; + + if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) + return(-EFAULT); + __get_user(i, &mp32->msg_name); + mp->msg_name = (void *)i; + __get_user(mp->msg_namelen, &mp32->msg_namelen); + __get_user(i, &mp32->msg_iov); + mp->msg_iov = (struct iov *)i; + __get_user(mp->msg_iovlen, &mp32->msg_iovlen); + __get_user(i, &mp32->msg_control); + mp->msg_control = (void *)i; + __get_user(mp->msg_controllen, &mp32->msg_controllen); + __get_user(mp->msg_flags, &mp32->msg_flags); + return(0); +} + +/* + * Verify & re-shape IA32 iovec. The caller must ensure that the + * iovec is big enough to hold the re-shaped message iovec. + * + * Save time not doing verify_area. copy_*_user will make this work + * in any case. + * + * Don't need to check the total size for overflow (cf net/core/iovec.c), + * 32-bit sizes can't overflow a 64-bit count. + */ + +static inline int +verify_iovec32(struct msghdr *m, struct iovec *iov, char *address, int mode) +{ + int size, err, ct; + struct iovec32 *iov32; + + if(m->msg_namelen) + { + if(mode==VERIFY_READ) + { + err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); + if(err<0) + goto out; + } + + m->msg_name = address; + } else + m->msg_name = NULL; + + err = -EFAULT; + size = m->msg_iovlen * sizeof(struct iovec32); + if (copy_from_user(iov, m->msg_iov, size)) + goto out; + m->msg_iov=iov; + + err = 0; + iov32 = (struct iovec32 *)iov; + for (ct = m->msg_iovlen; ct-- > 0; ) { + iov[ct].iov_len = (__kernel_size_t)iov32[ct].iov_len; + iov[ct].iov_base = (void *)iov32[ct].iov_base; + err += iov[ct].iov_len; + } +out: + return err; +} + +extern __inline__ void +sockfd_put(struct socket *sock) +{ + fput(sock->file); +} + +/* XXX This really belongs in some header file... -DaveM */ +#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - + 16 for IP, 16 for IPX, + 24 for IPv6, + about 80 for AX.25 */ + +extern struct socket *sockfd_lookup(int fd, int *err); + +/* + * BSD sendmsg interface + */ + +asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags) +{ + struct socket *sock; + char address[MAX_SOCK_ADDR]; + struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; + unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */ + unsigned char *ctl_buf = ctl; + struct msghdr msg_sys; + int err, ctl_len, iov_size, total_len; + + err = -EFAULT; + if (shape_msg(&msg_sys, msg)) + goto out; + + sock = sockfd_lookup(fd, &err); + if (!sock) + goto out; + + /* do not move before msg_sys is valid */ + err = -EINVAL; + if (msg_sys.msg_iovlen > UIO_MAXIOV) + goto out_put; + + /* Check whether to allocate the iovec area*/ + err = -ENOMEM; + iov_size = msg_sys.msg_iovlen * sizeof(struct iovec32); + if (msg_sys.msg_iovlen > UIO_FASTIOV) { + iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); + if (!iov) + goto out_put; + } + + /* This will also move the address data into kernel space */ + err = verify_iovec32(&msg_sys, iov, address, VERIFY_READ); + if (err < 0) + goto out_freeiov; + total_len = err; + + err = -ENOBUFS; + + if (msg_sys.msg_controllen > INT_MAX) + goto out_freeiov; + ctl_len = msg_sys.msg_controllen; + if (ctl_len) + { + if (ctl_len > sizeof(ctl)) + { + err = -ENOBUFS; + ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); + if (ctl_buf == NULL) + goto out_freeiov; + } + err = -EFAULT; + if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len)) + goto out_freectl; + msg_sys.msg_control = ctl_buf; + } + msg_sys.msg_flags = flags; + + if (sock->file->f_flags & O_NONBLOCK) + msg_sys.msg_flags |= MSG_DONTWAIT; + err = sock_sendmsg(sock, &msg_sys, total_len); + +out_freectl: + if (ctl_buf != ctl) + sock_kfree_s(sock->sk, ctl_buf, ctl_len); +out_freeiov: + if (iov != iovstack) + sock_kfree_s(sock->sk, iov, iov_size); +out_put: + sockfd_put(sock); +out: + return err; +} + +/* + * BSD recvmsg interface + */ + +asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *msg, unsigned int flags) +{ + struct socket *sock; + struct iovec iovstack[UIO_FASTIOV]; + struct iovec *iov=iovstack; + struct msghdr msg_sys; + unsigned long cmsg_ptr; + int err, iov_size, total_len, len; + + /* kernel mode address */ + char addr[MAX_SOCK_ADDR]; + + /* user mode address pointers */ + struct sockaddr *uaddr; + int *uaddr_len; + + err=-EFAULT; + if (shape_msg(&msg_sys, msg)) + goto out; + + sock = sockfd_lookup(fd, &err); + if (!sock) + goto out; + + err = -EINVAL; + if (msg_sys.msg_iovlen > UIO_MAXIOV) + goto out_put; + + /* Check whether to allocate the iovec area*/ + err = -ENOMEM; + iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); + if (msg_sys.msg_iovlen > UIO_FASTIOV) { + iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); + if (!iov) + goto out_put; + } + + /* + * Save the user-mode address (verify_iovec will change the + * kernel msghdr to use the kernel address space) + */ + + uaddr = msg_sys.msg_name; + uaddr_len = &msg->msg_namelen; + err = verify_iovec32(&msg_sys, iov, addr, VERIFY_WRITE); + if (err < 0) + goto out_freeiov; + total_len=err; + + cmsg_ptr = (unsigned long)msg_sys.msg_control; + msg_sys.msg_flags = 0; + + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + err = sock_recvmsg(sock, &msg_sys, total_len, flags); + if (err < 0) + goto out_freeiov; + len = err; + + if (uaddr != NULL) { + err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); + if (err < 0) + goto out_freeiov; + } + err = __put_user(msg_sys.msg_flags, &msg->msg_flags); + if (err) + goto out_freeiov; + err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, + &msg->msg_controllen); + if (err) + goto out_freeiov; + err = len; + +out_freeiov: + if (iov != iovstack) + sock_kfree_s(sock->sk, iov, iov_size); +out_put: + sockfd_put(sock); +out: + return err; +} + +/* + * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.. + * + * This is really horribly ugly. + */ + +struct msgbuf32 { s32 mtype; char mtext[1]; }; + +struct ipc_perm32 +{ + key_t key; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_uid_t32 cuid; + __kernel_gid_t32 cgid; + __kernel_mode_t32 mode; + unsigned short seq; +}; + +struct semid_ds32 { + struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t32 sem_otime; /* last semop time */ + __kernel_time_t32 sem_ctime; /* last change time */ + u32 sem_base; /* ptr to first semaphore in array */ + u32 sem_pending; /* pending operations to be processed */ + u32 sem_pending_last; /* last pending operation */ + u32 undo; /* undo requests on this array */ + unsigned short sem_nsems; /* no. of semaphores in array */ +}; + +struct msqid_ds32 +{ + struct ipc_perm32 msg_perm; + u32 msg_first; + u32 msg_last; + __kernel_time_t32 msg_stime; + __kernel_time_t32 msg_rtime; + __kernel_time_t32 msg_ctime; + u32 wwait; + u32 rwait; + unsigned short msg_cbytes; + unsigned short msg_qnum; + unsigned short msg_qbytes; + __kernel_ipc_pid_t32 msg_lspid; + __kernel_ipc_pid_t32 msg_lrpid; +}; + +struct shmid_ds32 { + struct ipc_perm32 shm_perm; + int shm_segsz; + __kernel_time_t32 shm_atime; + __kernel_time_t32 shm_dtime; + __kernel_time_t32 shm_ctime; + __kernel_ipc_pid_t32 shm_cpid; + __kernel_ipc_pid_t32 shm_lpid; + unsigned short shm_nattch; +}; + +#define IPCOP_MASK(__x) (1UL << (__x)) + +static int +do_sys32_semctl(int first, int second, int third, void *uptr) +{ + union semun fourth; + u32 pad; + int err = -EINVAL; + + if (!uptr) + goto out; + err = -EFAULT; + if (get_user (pad, (u32 *)uptr)) + goto out; + if(third == SETVAL) + fourth.val = (int)pad; + else + fourth.__pad = (void *)A(pad); + if (IPCOP_MASK (third) & + (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | + IPCOP_MASK (GETVAL) | IPCOP_MASK (GETPID) | + IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) | + IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) | + IPCOP_MASK (IPC_RMID))) { + err = sys_semctl (first, second, third, fourth); + } else { + struct semid_ds s; + struct semid_ds32 *usp = (struct semid_ds32 *)A(pad); + mm_segment_t old_fs; + int need_back_translation; + + if (third == IPC_SET) { + err = get_user (s.sem_perm.uid, &usp->sem_perm.uid); + err |= __get_user(s.sem_perm.gid, &usp->sem_perm.gid); + err |= __get_user(s.sem_perm.mode, &usp->sem_perm.mode); + if (err) + goto out; + fourth.__pad = &s; + } + need_back_translation = + (IPCOP_MASK (third) & + (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0; + if (need_back_translation) + fourth.__pad = &s; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_semctl (first, second, third, fourth); + set_fs (old_fs); + if (need_back_translation) { + int err2 = put_user(s.sem_perm.key, &usp->sem_perm.key); + err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid); + err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid); + err2 |= __put_user(s.sem_perm.cuid, + &usp->sem_perm.cuid); + err2 |= __put_user (s.sem_perm.cgid, + &usp->sem_perm.cgid); + err2 |= __put_user (s.sem_perm.mode, + &usp->sem_perm.mode); + err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); + err2 |= __put_user (s.sem_otime, &usp->sem_otime); + err2 |= __put_user (s.sem_ctime, &usp->sem_ctime); + err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); + if (err2) err = -EFAULT; + } + } +out: + return err; +} + +static int +do_sys32_msgsnd (int first, int second, int third, void *uptr) +{ + struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + + 4, GFP_USER); + struct msgbuf32 *up = (struct msgbuf32 *)uptr; + mm_segment_t old_fs; + int err; + + if (!p) + return -ENOMEM; + err = get_user (p->mtype, &up->mtype); + err |= __copy_from_user (p->mtext, &up->mtext, second); + if (err) + goto out; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgsnd (first, p, second, third); + set_fs (old_fs); +out: + kfree (p); + return err; +} + +static int +do_sys32_msgrcv (int first, int second, int msgtyp, int third, + int version, void *uptr) +{ + struct msgbuf32 *up; + struct msgbuf *p; + mm_segment_t old_fs; + int err; + + if (!version) { + struct ipc_kludge *uipck = (struct ipc_kludge *)uptr; + struct ipc_kludge ipck; + + err = -EINVAL; + if (!uptr) + goto out; + err = -EFAULT; + if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge))) + goto out; + uptr = (void *)A(ipck.msgp); + msgtyp = ipck.msgtyp; + } + err = -ENOMEM; + p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); + if (!p) + goto out; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgrcv (first, p, second + 4, msgtyp, third); + set_fs (old_fs); + if (err < 0) + goto free_then_out; + up = (struct msgbuf32 *)uptr; + if (put_user (p->mtype, &up->mtype) || + __copy_to_user (&up->mtext, p->mtext, err)) + err = -EFAULT; +free_then_out: + kfree (p); +out: + return err; +} + +static int +do_sys32_msgctl (int first, int second, void *uptr) +{ + int err; + + if (IPCOP_MASK (second) & + (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (MSG_INFO) | + IPCOP_MASK (IPC_RMID))) { + err = sys_msgctl (first, second, (struct msqid_ds *)uptr); + } else { + struct msqid_ds m; + struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; + mm_segment_t old_fs; + + if (second == IPC_SET) { + err = get_user (m.msg_perm.uid, &up->msg_perm.uid); + err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid); + err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode); + err |= __get_user (m.msg_qbytes, &up->msg_qbytes); + if (err) + goto out; + } + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgctl (first, second, &m); + set_fs (old_fs); + if (IPCOP_MASK (second) & + (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) { + int err2 = put_user (m.msg_perm.key, &up->msg_perm.key); + err2 |= __put_user(m.msg_perm.uid, &up->msg_perm.uid); + err2 |= __put_user(m.msg_perm.gid, &up->msg_perm.gid); + err2 |= __put_user(m.msg_perm.cuid, &up->msg_perm.cuid); + err2 |= __put_user(m.msg_perm.cgid, &up->msg_perm.cgid); + err2 |= __put_user(m.msg_perm.mode, &up->msg_perm.mode); + err2 |= __put_user(m.msg_perm.seq, &up->msg_perm.seq); + err2 |= __put_user(m.msg_stime, &up->msg_stime); + err2 |= __put_user(m.msg_rtime, &up->msg_rtime); + err2 |= __put_user(m.msg_ctime, &up->msg_ctime); + err2 |= __put_user(m.msg_cbytes, &up->msg_cbytes); + err2 |= __put_user(m.msg_qnum, &up->msg_qnum); + err2 |= __put_user(m.msg_qbytes, &up->msg_qbytes); + err2 |= __put_user(m.msg_lspid, &up->msg_lspid); + err2 |= __put_user(m.msg_lrpid, &up->msg_lrpid); + if (err2) + err = -EFAULT; + } + } + +out: + return err; +} + +static int +do_sys32_shmat (int first, int second, int third, int version, void *uptr) +{ + unsigned long raddr; + u32 *uaddr = (u32 *)A((u32)third); + int err = -EINVAL; + + if (version == 1) + goto out; + err = sys_shmat (first, uptr, second, &raddr); + if (err) + goto out; + err = put_user (raddr, uaddr); +out: + return err; +} + +static int +do_sys32_shmctl (int first, int second, void *uptr) +{ + int err; + + if (IPCOP_MASK (second) & + (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SHM_LOCK) + | IPCOP_MASK (SHM_UNLOCK) | IPCOP_MASK (IPC_RMID))) { + err = sys_shmctl (first, second, (struct shmid_ds *)uptr); + } else { + struct shmid_ds s; + struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; + mm_segment_t old_fs; + + if (second == IPC_SET) { + err = get_user (s.shm_perm.uid, &up->shm_perm.uid); + err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); + err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode); + if (err) + goto out; + } + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_shmctl (first, second, &s); + set_fs (old_fs); + if (err < 0) + goto out; + + /* Mask it even in this case so it becomes a CSE. */ + if (second == SHM_INFO) { + struct shm_info32 { + int used_ids; + u32 shm_tot, shm_rss, shm_swp; + u32 swap_attempts, swap_successes; + } *uip = (struct shm_info32 *)uptr; + struct shm_info *kp = (struct shm_info *)&s; + int err2 = put_user (kp->used_ids, &uip->used_ids); + err2 |= __put_user (kp->shm_tot, &uip->shm_tot); + err2 |= __put_user (kp->shm_rss, &uip->shm_rss); + err2 |= __put_user (kp->shm_swp, &uip->shm_swp); + err2 |= __put_user (kp->swap_attempts, + &uip->swap_attempts); + err2 |= __put_user (kp->swap_successes, + &uip->swap_successes); + if (err2) + err = -EFAULT; + } else if (IPCOP_MASK (second) & + (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) { + int err2 = put_user (s.shm_perm.key, &up->shm_perm.key); + err2 |= __put_user (s.shm_perm.uid, &up->shm_perm.uid); + err2 |= __put_user (s.shm_perm.gid, &up->shm_perm.gid); + err2 |= __put_user (s.shm_perm.cuid, + &up->shm_perm.cuid); + err2 |= __put_user (s.shm_perm.cgid, + &up->shm_perm.cgid); + err2 |= __put_user (s.shm_perm.mode, + &up->shm_perm.mode); + err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq); + err2 |= __put_user (s.shm_atime, &up->shm_atime); + err2 |= __put_user (s.shm_dtime, &up->shm_dtime); + err2 |= __put_user (s.shm_ctime, &up->shm_ctime); + err2 |= __put_user (s.shm_segsz, &up->shm_segsz); + err2 |= __put_user (s.shm_nattch, &up->shm_nattch); + err2 |= __put_user (s.shm_cpid, &up->shm_cpid); + err2 |= __put_user (s.shm_lpid, &up->shm_lpid); + if (err2) + err = -EFAULT; + } + } +out: + return err; +} + +asmlinkage int +sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) +{ + int version, err; + + lock_kernel(); + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + /* struct sembuf is the same on 32 and 64bit :)) */ + err = sys_semop (first, (struct sembuf *)AA(ptr), + second); + goto out; + case SEMGET: + err = sys_semget (first, second, third); + goto out; + case SEMCTL: + err = do_sys32_semctl (first, second, third, + (void *)AA(ptr)); + goto out; + default: + err = -EINVAL; + goto out; + }; + if (call <= MSGCTL) + switch (call) { + case MSGSND: + err = do_sys32_msgsnd (first, second, third, + (void *)AA(ptr)); + goto out; + case MSGRCV: + err = do_sys32_msgrcv (first, second, fifth, third, + version, (void *)AA(ptr)); + goto out; + case MSGGET: + err = sys_msgget ((key_t) first, second); + goto out; + case MSGCTL: + err = do_sys32_msgctl (first, second, (void *)AA(ptr)); + goto out; + default: + err = -EINVAL; + goto out; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + err = do_sys32_shmat (first, second, third, + version, (void *)AA(ptr)); + goto out; + case SHMDT: + err = sys_shmdt ((char *)AA(ptr)); + goto out; + case SHMGET: + err = sys_shmget (first, second, third); + goto out; + case SHMCTL: + err = do_sys32_shmctl (first, second, (void *)AA(ptr)); + goto out; + default: + err = -EINVAL; + goto out; + } + + err = -EINVAL; + +out: + unlock_kernel(); + return err; +} + +#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ + +/* In order to reduce some races, while at the same time doing additional + * checking and hopefully speeding things up, we copy filenames to the + * kernel data space before using them.. + * + * POSIX.1 2.4: an empty pathname is invalid (ENOENT). + */ +static inline int +do_getname32(const char *filename, char *page) +{ + int retval; + + /* 32bit pointer will be always far below TASK_SIZE :)) */ + retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE); + if (retval > 0) { + if (retval < PAGE_SIZE) + return 0; + return -ENAMETOOLONG; + } else if (!retval) + retval = -ENOENT; + return retval; +} + +char * +getname32(const char *filename) +{ + char *tmp, *result; + + result = ERR_PTR(-ENOMEM); + tmp = (char *)__get_free_page(GFP_KERNEL); + if (tmp) { + int retval = do_getname32(filename, tmp); + + result = tmp; + if (retval < 0) { + putname(tmp); + result = ERR_PTR(retval); + } + } + return result; +} + +/* 32-bit timeval and related flotsam. */ + +extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); + +asmlinkage int +sys32_ioperm(u32 from, u32 num, int on) +{ + return sys_ioperm((unsigned long)from, (unsigned long)num, on); +} + +static inline int +get_flock(struct flock *kfl, struct flock32 *ufl) +{ + int err; + + err = get_user(kfl->l_type, &ufl->l_type); + err |= __get_user(kfl->l_whence, &ufl->l_whence); + err |= __get_user(kfl->l_start, &ufl->l_start); + err |= __get_user(kfl->l_len, &ufl->l_len); + err |= __get_user(kfl->l_pid, &ufl->l_pid); + return err; +} + +static inline int +put_flock(struct flock *kfl, struct flock32 *ufl) +{ + int err; + + err = __put_user(kfl->l_type, &ufl->l_type); + err |= __put_user(kfl->l_whence, &ufl->l_whence); + err |= __put_user(kfl->l_start, &ufl->l_start); + err |= __put_user(kfl->l_len, &ufl->l_len); + err |= __put_user(kfl->l_pid, &ufl->l_pid); + return err; +} + +extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, + unsigned long arg); + +asmlinkage long +sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + { + struct flock f; + mm_segment_t old_fs; + long ret; + + if(get_flock(&f, (struct flock32 *)arg)) + return -EFAULT; + old_fs = get_fs(); set_fs (KERNEL_DS); + ret = sys_fcntl(fd, cmd, (unsigned long)&f); + set_fs (old_fs); + if(put_flock(&f, (struct flock32 *)arg)) + return -EFAULT; + return ret; + } + default: + return sys_fcntl(fd, cmd, (unsigned long)arg); + } +} + +struct dqblk32 { + __u32 dqb_bhardlimit; + __u32 dqb_bsoftlimit; + __u32 dqb_curblocks; + __u32 dqb_ihardlimit; + __u32 dqb_isoftlimit; + __u32 dqb_curinodes; + __kernel_time_t32 dqb_btime; + __kernel_time_t32 dqb_itime; +}; + +extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, + 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; + mm_segment_t old_fs; + char *spec; + + switch (cmds) { + case Q_GETQUOTA: + break; + case Q_SETQUOTA: + case Q_SETUSE: + case Q_SETQLIM: + if (copy_from_user (&d, (struct dqblk32 *)addr, + sizeof (struct dqblk32))) + return -EFAULT; + d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; + d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; + break; + default: + return sys_quotactl(cmd, special, + id, (caddr_t)addr); + } + spec = getname32 (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); + set_fs (old_fs); + putname (spec); + 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))) + return -EFAULT; + } + return err; +} + +extern asmlinkage int sys_utime(char * filename, struct utimbuf * times); + +struct utimbuf32 { + __kernel_time_t32 actime, modtime; +}; + +asmlinkage int +sys32_utime(char * filename, struct utimbuf32 *times) +{ + struct utimbuf t; + mm_segment_t old_fs; + int ret; + char *filenam; + + if (!times) + return sys_utime(filename, NULL); + if (get_user (t.actime, ×->actime) || + __get_user (t.modtime, ×->modtime)) + return -EFAULT; + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { + old_fs = get_fs(); + set_fs (KERNEL_DS); + ret = sys_utime(filenam, &t); + set_fs (old_fs); + putname (filenam); + } + return ret; +} + +/* + * Ooo, nasty. We need here to frob 32-bit unsigned longs to + * 64-bit unsigned longs. + */ + +static inline int +get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset) +{ + if (ufdset) { + unsigned long odd; + + if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32))) + return -EFAULT; + + odd = n & 1UL; + n &= ~1UL; + while (n) { + unsigned long h, l; + __get_user(l, ufdset); + __get_user(h, ufdset+1); + ufdset += 2; + *fdset++ = h << 32 | l; + n -= 2; + } + if (odd) + __get_user(*fdset, ufdset); + } else { + /* Tricky, must clear full unsigned long in the + * kernel fdset at the end, this makes sure that + * actually happens. + */ + memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32)); + } + return 0; +} + +static inline void +set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset) +{ + unsigned long odd; + + if (!ufdset) + return; + + odd = n & 1UL; + n &= ~1UL; + while (n) { + unsigned long h, l; + l = *fdset++; + h = l >> 32; + __put_user(l, ufdset); + __put_user(h, ufdset+1); + ufdset += 2; + n -= 2; + } + if (odd) + __put_user(*fdset, ufdset); +} + +extern asmlinkage int sys_sysfs(int option, unsigned long arg1, + unsigned long arg2); + +asmlinkage int +sys32_sysfs(int option, u32 arg1, u32 arg2) +{ + return sys_sysfs(option, arg1, arg2); +} + +struct ncp_mount_data32 { + int version; + unsigned int ncp_fd; + __kernel_uid_t32 mounted_uid; + __kernel_pid_t32 wdog_pid; + unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; + unsigned int time_out; + unsigned int retry_count; + unsigned int flags; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; +}; + +static void * +do_ncp_super_data_conv(void *raw_data) +{ + struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data; + struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data; + + n->dir_mode = n32->dir_mode; + n->file_mode = n32->file_mode; + n->gid = n32->gid; + n->uid = n32->uid; + memmove (n->mounted_vol, n32->mounted_vol, + (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int))); + n->wdog_pid = n32->wdog_pid; + n->mounted_uid = n32->mounted_uid; + return raw_data; +} + +struct smb_mount_data32 { + int version; + __kernel_uid_t32 mounted_uid; + __kernel_uid_t32 uid; + __kernel_gid_t32 gid; + __kernel_mode_t32 file_mode; + __kernel_mode_t32 dir_mode; +}; + +static void * +do_smb_super_data_conv(void *raw_data) +{ + struct smb_mount_data *s = (struct smb_mount_data *)raw_data; + struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; + + s->version = s32->version; + s->mounted_uid = s32->mounted_uid; + s->uid = s32->uid; + s->gid = s32->gid; + s->file_mode = s32->file_mode; + s->dir_mode = s32->dir_mode; + return raw_data; +} + +static int +copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel) +{ + int i; + unsigned long page; + struct vm_area_struct *vma; + + *kernel = 0; + if(!user) + return 0; + vma = find_vma(current->mm, (unsigned long)user); + if(!vma || (unsigned long)user < vma->vm_start) + return -EFAULT; + if(!(vma->vm_flags & VM_READ)) + return -EFAULT; + i = vma->vm_end - (unsigned long) user; + if(PAGE_SIZE <= (unsigned long) i) + i = PAGE_SIZE - 1; + if(!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + if(copy_from_user((void *) page, user, i)) { + free_page(page); + return -EFAULT; + } + *kernel = page; + return 0; +} + +extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void *data); + +#define SMBFS_NAME "smbfs" +#define NCPFS_NAME "ncpfs" + +asmlinkage int +sys32_mount(char *dev_name, char *dir_name, char *type, + unsigned long new_flags, u32 data) +{ + unsigned long type_page; + int err, is_smb, is_ncp; + + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + is_smb = is_ncp = 0; + err = copy_mount_stuff_to_kernel((const void *)type, &type_page); + if(err) + return err; + if(type_page) { + is_smb = !strcmp((char *)type_page, SMBFS_NAME); + is_ncp = !strcmp((char *)type_page, NCPFS_NAME); + } + if(!is_smb && !is_ncp) { + if(type_page) + free_page(type_page); + return sys_mount(dev_name, dir_name, type, new_flags, + (void *)AA(data)); + } else { + unsigned long dev_page, dir_page, data_page; + mm_segment_t old_fs; + + err = copy_mount_stuff_to_kernel((const void *)dev_name, + &dev_page); + if(err) + goto out; + err = copy_mount_stuff_to_kernel((const void *)dir_name, + &dir_page); + if(err) + goto dev_out; + err = copy_mount_stuff_to_kernel((const void *)AA(data), + &data_page); + if(err) + goto dir_out; + if(is_ncp) + do_ncp_super_data_conv((void *)data_page); + else if(is_smb) + do_smb_super_data_conv((void *)data_page); + else + panic("The problem is here..."); + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_mount((char *)dev_page, (char *)dir_page, + (char *)type_page, new_flags, + (void *)data_page); + set_fs(old_fs); + + if(data_page) + free_page(data_page); + dir_out: + if(dir_page) + free_page(dir_page); + dev_out: + if(dev_page) + free_page(dev_page); + out: + if(type_page) + free_page(type_page); + return err; + } +} + +struct sysinfo32 { + s32 uptime; + u32 loads[3]; + u32 totalram; + u32 freeram; + u32 sharedram; + u32 bufferram; + u32 totalswap; + u32 freeswap; + unsigned short procs; + char _f[22]; +}; + +extern asmlinkage int sys_sysinfo(struct sysinfo *info); + +asmlinkage int +sys32_sysinfo(struct sysinfo32 *info) +{ + struct sysinfo s; + int ret, err; + mm_segment_t old_fs = get_fs (); + + set_fs (KERNEL_DS); + ret = sys_sysinfo(&s); + set_fs (old_fs); + err = put_user (s.uptime, &info->uptime); + err |= __put_user (s.loads[0], &info->loads[0]); + err |= __put_user (s.loads[1], &info->loads[1]); + err |= __put_user (s.loads[2], &info->loads[2]); + err |= __put_user (s.totalram, &info->totalram); + err |= __put_user (s.freeram, &info->freeram); + err |= __put_user (s.sharedram, &info->sharedram); + err |= __put_user (s.bufferram, &info->bufferram); + err |= __put_user (s.totalswap, &info->totalswap); + err |= __put_user (s.freeswap, &info->freeswap); + err |= __put_user (s.procs, &info->procs); + if (err) + return -EFAULT; + return ret; +} + +extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, + struct timespec *interval); + +asmlinkage int +sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval) +{ + struct timespec t; + int ret; + mm_segment_t old_fs = get_fs (); + + set_fs (KERNEL_DS); + ret = sys_sched_rr_get_interval(pid, &t); + set_fs (old_fs); + if (put_user (t.tv_sec, &interval->tv_sec) || + __put_user (t.tv_nsec, &interval->tv_nsec)) + return -EFAULT; + return ret; +} + +extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, + old_sigset_t *oset); + +asmlinkage int +sys32_sigprocmask(int how, old_sigset_t32 *set, old_sigset_t32 *oset) +{ + old_sigset_t s; + int ret; + mm_segment_t old_fs = get_fs(); + + if (set && get_user (s, set)) return -EFAULT; + set_fs (KERNEL_DS); + ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); + set_fs (old_fs); + if (ret) return ret; + if (oset && put_user (s, oset)) return -EFAULT; + return 0; +} + +extern asmlinkage int sys_sigpending(old_sigset_t *set); + +asmlinkage int +sys32_sigpending(old_sigset_t32 *set) +{ + old_sigset_t s; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_sigpending(&s); + set_fs (old_fs); + if (put_user (s, set)) return -EFAULT; + return ret; +} + +extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize); + +asmlinkage int +sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize) +{ + sigset_t s; + sigset_t32 s32; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_rt_sigpending(&s, sigsetsize); + set_fs (old_fs); + if (!ret) { + switch (_NSIG_WORDS) { + case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; + case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; + case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; + case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; + } + if (copy_to_user (set, &s32, sizeof(sigset_t32))) + return -EFAULT; + } + return ret; +} + +siginfo_t32 * +siginfo64to32(siginfo_t32 *d, siginfo_t *s) +{ + memset (&d, 0, sizeof(siginfo_t32)); + d->si_signo = s->si_signo; + d->si_errno = s->si_errno; + d->si_code = s->si_code; + if (s->si_signo >= SIGRTMIN) { + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + /* XXX: Ouch, how to find this out??? */ + d->si_int = s->si_int; + } else switch (s->si_signo) { + /* XXX: What about POSIX1.b timers */ + case SIGCHLD: + d->si_pid = s->si_pid; + d->si_status = s->si_status; + d->si_utime = s->si_utime; + d->si_stime = s->si_stime; + break; + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + d->si_addr = (long)(s->si_addr); + /* XXX: Do we need to translate this from ia64 to ia32 traps? */ + d->si_trapno = s->si_trapno; + break; + case SIGPOLL: + d->si_band = s->si_band; + d->si_fd = s->si_fd; + break; + default: + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + break; + } + return d; +} + +siginfo_t * +siginfo32to64(siginfo_t *d, siginfo_t32 *s) +{ + d->si_signo = s->si_signo; + d->si_errno = s->si_errno; + d->si_code = s->si_code; + if (s->si_signo >= SIGRTMIN) { + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + /* XXX: Ouch, how to find this out??? */ + d->si_int = s->si_int; + } else switch (s->si_signo) { + /* XXX: What about POSIX1.b timers */ + case SIGCHLD: + d->si_pid = s->si_pid; + d->si_status = s->si_status; + d->si_utime = s->si_utime; + d->si_stime = s->si_stime; + break; + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + d->si_addr = (void *)A(s->si_addr); + /* XXX: Do we need to translate this from ia32 to ia64 traps? */ + d->si_trapno = s->si_trapno; + break; + case SIGPOLL: + d->si_band = s->si_band; + d->si_fd = s->si_fd; + break; + default: + d->si_pid = s->si_pid; + d->si_uid = s->si_uid; + break; + } + return d; +} + +extern asmlinkage int +sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, + const struct timespec *uts, size_t sigsetsize); + +asmlinkage int +sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, + struct timespec32 *uts, __kernel_size_t32 sigsetsize) +{ + sigset_t s; + sigset_t32 s32; + struct timespec t; + int ret; + mm_segment_t old_fs = get_fs(); + siginfo_t info; + siginfo_t32 info32; + + if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) + return -EFAULT; + switch (_NSIG_WORDS) { + case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); + case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); + case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); + case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); + } + if (uts) { + ret = get_user (t.tv_sec, &uts->tv_sec); + ret |= __get_user (t.tv_nsec, &uts->tv_nsec); + if (ret) + return -EFAULT; + } + set_fs (KERNEL_DS); + ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); + set_fs (old_fs); + if (ret >= 0 && uinfo) { + if (copy_to_user (uinfo, siginfo64to32(&info32, &info), + sizeof(siginfo_t32))) + return -EFAULT; + } + return ret; +} + +extern asmlinkage int +sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); + +asmlinkage int +sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) +{ + siginfo_t info; + siginfo_t32 info32; + int ret; + mm_segment_t old_fs = get_fs(); + + if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) + return -EFAULT; + /* XXX: Is this correct? */ + siginfo32to64(&info, &info32); + set_fs (KERNEL_DS); + ret = sys_rt_sigqueueinfo(pid, sig, &info); + set_fs (old_fs); + return ret; +} + +extern asmlinkage int sys_setreuid(uid_t ruid, uid_t euid); + +asmlinkage int sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) +{ + uid_t sruid, seuid; + + sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); + seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); + return sys_setreuid(sruid, seuid); +} + +extern asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); + +asmlinkage int +sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid, + __kernel_uid_t32 suid) +{ + uid_t sruid, seuid, ssuid; + + sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); + seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); + ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); + return sys_setresuid(sruid, seuid, ssuid); +} + +extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); + +asmlinkage int +sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid, + __kernel_uid_t32 *suid) +{ + uid_t a, b, c; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_getresuid(&a, &b, &c); + set_fs (old_fs); + if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid)) + return -EFAULT; + return ret; +} + +extern asmlinkage int sys_setregid(gid_t rgid, gid_t egid); + +asmlinkage int +sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) +{ + gid_t srgid, segid; + + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + return sys_setregid(srgid, segid); +} + +extern asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); + +asmlinkage int +sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid, + __kernel_gid_t32 sgid) +{ + gid_t srgid, segid, ssgid; + + srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); + segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); + ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); + return sys_setresgid(srgid, segid, ssgid); +} + +extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); + +asmlinkage int +sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, + __kernel_gid_t32 *sgid) +{ + gid_t a, b, c; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_getresgid(&a, &b, &c); + set_fs (old_fs); + if (!ret) { + ret = put_user (a, rgid); + ret |= put_user (b, egid); + ret |= put_user (c, sgid); + } + return ret; +} + +struct tms32 { + __kernel_clock_t32 tms_utime; + __kernel_clock_t32 tms_stime; + __kernel_clock_t32 tms_cutime; + __kernel_clock_t32 tms_cstime; +}; + +extern asmlinkage long sys_times(struct tms * tbuf); + +asmlinkage long +sys32_times(struct tms32 *tbuf) +{ + struct tms t; + long ret; + mm_segment_t old_fs = get_fs (); + int err; + + set_fs (KERNEL_DS); + ret = sys_times(tbuf ? &t : NULL); + set_fs (old_fs); + if (tbuf) { + err = put_user (t.tms_utime, &tbuf->tms_utime); + err |= __put_user (t.tms_stime, &tbuf->tms_stime); + err |= __put_user (t.tms_cutime, &tbuf->tms_cutime); + err |= __put_user (t.tms_cstime, &tbuf->tms_cstime); + if (err) + ret = -EFAULT; + } + return ret; +} + +extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist); + +asmlinkage int +sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist) +{ + gid_t gl[NGROUPS]; + int ret, i; + mm_segment_t old_fs = get_fs (); + + set_fs (KERNEL_DS); + ret = sys_getgroups(gidsetsize, gl); + set_fs (old_fs); + if (gidsetsize && ret > 0 && ret <= NGROUPS) + for (i = 0; i < ret; i++, grouplist++) + if (__put_user (gl[i], grouplist)) + return -EFAULT; + return ret; +} + +extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist); + +asmlinkage int +sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist) +{ + gid_t gl[NGROUPS]; + int ret, i; + mm_segment_t old_fs = get_fs (); + + if ((unsigned) gidsetsize > NGROUPS) + return -EINVAL; + for (i = 0; i < gidsetsize; i++, grouplist++) + if (__get_user (gl[i], grouplist)) + return -EFAULT; + set_fs (KERNEL_DS); + ret = sys_setgroups(gidsetsize, gl); + set_fs (old_fs); + return ret; +} + +extern asmlinkage int +sys_getrusage(int who, struct rusage *ru); + +asmlinkage int +sys32_getrusage(int who, struct rusage32 *ru) +{ + struct rusage r; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_getrusage(who, &r); + set_fs (old_fs); + if (put_rusage (ru, &r)) return -EFAULT; + return ret; +} + + +/* XXX These as well... */ +extern __inline__ struct socket * +socki_lookup(struct inode *inode) +{ + return &inode->u.socket_i; +} + +extern __inline__ struct socket * +sockfd_lookup(int fd, int *err) +{ + struct file *file; + struct inode *inode; + + if (!(file = fget(fd))) + { + *err = -EBADF; + return NULL; + } + + inode = file->f_dentry->d_inode; + if (!inode || !inode->i_sock || !socki_lookup(inode)) + { + *err = -ENOTSOCK; + fput(file); + return NULL; + } + + return socki_lookup(inode); +} + +struct msghdr32 { + u32 msg_name; + int msg_namelen; + u32 msg_iov; + __kernel_size_t32 msg_iovlen; + u32 msg_control; + __kernel_size_t32 msg_controllen; + unsigned msg_flags; +}; + +struct cmsghdr32 { + __kernel_size_t32 cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +/* Bleech... */ +#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) \ + __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen)) +#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) \ + cmsg32_nxthdr((mhdr), (cmsg), (cmsglen)) + +#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) ) + +#define CMSG32_DATA(cmsg) \ + ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32)))) +#define CMSG32_SPACE(len) \ + (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len)) +#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len)) + +#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \ + (struct cmsghdr32 *)(ctl) : \ + (struct cmsghdr32 *)NULL) +#define CMSG32_FIRSTHDR(msg) \ + __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) + +__inline__ struct cmsghdr32 * +__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size, + struct cmsghdr32 *__cmsg, int __cmsg_len) +{ + struct cmsghdr32 * __ptr; + + __ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) + + CMSG32_ALIGN(__cmsg_len)); + if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) + return NULL; + + return __ptr; +} + +__inline__ struct cmsghdr32 * +cmsg32_nxthdr (struct msghdr *__msg, struct cmsghdr32 *__cmsg, int __cmsg_len) +{ + return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen, + __cmsg, __cmsg_len); +} + +static inline int +iov_from_user32_to_kern(struct iovec *kiov, struct iovec32 *uiov32, int niov) +{ + int tot_len = 0; + + while(niov > 0) { + u32 len, buf; + + if(get_user(len, &uiov32->iov_len) || + get_user(buf, &uiov32->iov_base)) { + tot_len = -EFAULT; + break; + } + tot_len += len; + kiov->iov_base = (void *)A(buf); + kiov->iov_len = (__kernel_size_t) len; + uiov32++; + kiov++; + niov--; + } + return tot_len; +} + +static inline int +msghdr_from_user32_to_kern(struct msghdr *kmsg, struct msghdr32 *umsg) +{ + u32 tmp1, tmp2, tmp3; + int err; + + err = get_user(tmp1, &umsg->msg_name); + err |= __get_user(tmp2, &umsg->msg_iov); + err |= __get_user(tmp3, &umsg->msg_control); + if (err) + return -EFAULT; + + kmsg->msg_name = (void *)A(tmp1); + kmsg->msg_iov = (struct iovec *)A(tmp2); + kmsg->msg_control = (void *)A(tmp3); + + err = get_user(kmsg->msg_namelen, &umsg->msg_namelen); + err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen); + err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); + err |= get_user(kmsg->msg_flags, &umsg->msg_flags); + + return err; +} + +/* I've named the args so it is easy to tell whose space the pointers are in. */ +static int +verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov, + char *kern_address, int mode) +{ + int tot_len; + + if(kern_msg->msg_namelen) { + if(mode==VERIFY_READ) { + int err = move_addr_to_kernel(kern_msg->msg_name, + kern_msg->msg_namelen, + kern_address); + if(err < 0) + return err; + } + kern_msg->msg_name = kern_address; + } else + kern_msg->msg_name = NULL; + + if(kern_msg->msg_iovlen > UIO_FASTIOV) { + kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec), + GFP_KERNEL); + if(!kern_iov) + return -ENOMEM; + } + + tot_len = iov_from_user32_to_kern(kern_iov, + (struct iovec32 *)kern_msg->msg_iov, + kern_msg->msg_iovlen); + if(tot_len >= 0) + kern_msg->msg_iov = kern_iov; + else if(kern_msg->msg_iovlen > UIO_FASTIOV) + kfree(kern_iov); + + return tot_len; +} + +/* There is a lot of hair here because the alignment rules (and + * thus placement) of cmsg headers and length are different for + * 32-bit apps. -DaveM + */ +static int +cmsghdr_from_user32_to_kern(struct msghdr *kmsg, unsigned char *stackbuf, + int stackbuf_size) +{ + struct cmsghdr32 *ucmsg; + struct cmsghdr *kcmsg, *kcmsg_base; + __kernel_size_t32 ucmlen; + __kernel_size_t kcmlen, tmp; + + kcmlen = 0; + kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; + ucmsg = CMSG32_FIRSTHDR(kmsg); + while(ucmsg != NULL) { + if(get_user(ucmlen, &ucmsg->cmsg_len)) + return -EFAULT; + + /* Catch bogons. */ + if(CMSG32_ALIGN(ucmlen) < + CMSG32_ALIGN(sizeof(struct cmsghdr32))) + return -EINVAL; + if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control) + + ucmlen) > kmsg->msg_controllen) + return -EINVAL; + + tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + + CMSG_ALIGN(sizeof(struct cmsghdr))); + kcmlen += tmp; + ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); + } + if(kcmlen == 0) + return -EINVAL; + + /* The kcmlen holds the 64-bit version of the control length. + * It may not be modified as we do not stick it into the kmsg + * until we have successfully copied over all of the data + * from the user. + */ + if(kcmlen > stackbuf_size) + kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL); + if(kcmsg == NULL) + return -ENOBUFS; + + /* Now copy them over neatly. */ + memset(kcmsg, 0, kcmlen); + ucmsg = CMSG32_FIRSTHDR(kmsg); + while(ucmsg != NULL) { + __get_user(ucmlen, &ucmsg->cmsg_len); + tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + + CMSG_ALIGN(sizeof(struct cmsghdr))); + kcmsg->cmsg_len = tmp; + __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); + __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); + + /* Copy over the data. */ + if(copy_from_user(CMSG_DATA(kcmsg), + CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) + goto out_free_efault; + + /* Advance. */ + kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); + } + + /* Ok, looks like we made it. Hook it up and return success. */ + kmsg->msg_control = kcmsg_base; + kmsg->msg_controllen = kcmlen; + return 0; + +out_free_efault: + if(kcmsg_base != (struct cmsghdr *)stackbuf) + kfree(kcmsg_base); + return -EFAULT; +} + +static void +put_cmsg32(struct msghdr *kmsg, int level, int type, int len, void *data) +{ + struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; + struct cmsghdr32 cmhdr; + int cmlen = CMSG32_LEN(len); + + if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { + kmsg->msg_flags |= MSG_CTRUNC; + return; + } + + if(kmsg->msg_controllen < cmlen) { + kmsg->msg_flags |= MSG_CTRUNC; + cmlen = kmsg->msg_controllen; + } + cmhdr.cmsg_level = level; + cmhdr.cmsg_type = type; + cmhdr.cmsg_len = cmlen; + + if(copy_to_user(cm, &cmhdr, sizeof cmhdr)) + return; + if(copy_to_user(CMSG32_DATA(cm), data, + cmlen - sizeof(struct cmsghdr32))) + return; + cmlen = CMSG32_SPACE(len); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; +} + +static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm) +{ + struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; + int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) + / sizeof(int); + int fdnum = scm->fp->count; + struct file **fp = scm->fp->fp; + int *cmfptr; + int err = 0, i; + + if (fdnum < fdmax) + fdmax = fdnum; + + for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); + i < fdmax; + i++, cmfptr++) { + int new_fd; + err = get_unused_fd(); + if (err < 0) + break; + new_fd = err; + err = put_user(new_fd, cmfptr); + if (err) { + put_unused_fd(new_fd); + break; + } + /* Bump the usage count and install the file. */ + fp[i]->f_count++; + current->files->fd[new_fd] = fp[i]; + } + + if (i > 0) { + int cmlen = CMSG32_LEN(i * sizeof(int)); + if (!err) + err = put_user(SOL_SOCKET, &cm->cmsg_level); + if (!err) + err = put_user(SCM_RIGHTS, &cm->cmsg_type); + if (!err) + err = put_user(cmlen, &cm->cmsg_len); + if (!err) { + cmlen = CMSG32_SPACE(i * sizeof(int)); + kmsg->msg_control += cmlen; + kmsg->msg_controllen -= cmlen; + } + } + if (i < fdnum) + kmsg->msg_flags |= MSG_CTRUNC; + + /* + * All of the files that fit in the message have had their + * usage counts incremented, so we just free the list. + */ + __scm_destroy(scm); +} + +/* In these cases we (currently) can just copy to data over verbatim + * because all CMSGs created by the kernel have well defined types which + * have the same layout in both the 32-bit and 64-bit API. One must add + * some special cased conversions here if we start sending control messages + * with incompatible types. + * + * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after + * we do our work. The remaining cases are: + * + * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean + * IP_TTL int 32-bit clean + * IP_TOS __u8 32-bit clean + * IP_RECVOPTS variable length 32-bit clean + * IP_RETOPTS variable length 32-bit clean + * (these last two are clean because the types are defined + * by the IPv4 protocol) + * IP_RECVERR struct sock_extended_err + + * struct sockaddr_in 32-bit clean + * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + + * struct sockaddr_in6 32-bit clean + * IPV6_PKTINFO struct in6_pktinfo 32-bit clean + * IPV6_HOPLIMIT int 32-bit clean + * IPV6_FLOWINFO u32 32-bit clean + * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean + * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean + * IPV6_RTHDR ipv6 routing exthdr 32-bit clean + * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean + */ +static void +cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr) +{ + unsigned char *workbuf, *wp; + unsigned long bufsz, space_avail; + struct cmsghdr *ucmsg; + + bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; + space_avail = kmsg->msg_controllen + bufsz; + wp = workbuf = kmalloc(bufsz, GFP_KERNEL); + if(workbuf == NULL) + goto fail; + + /* To make this more sane we assume the kernel sends back properly + * formatted control messages. Because of how the kernel will truncate + * the cmsg_len for MSG_TRUNC cases, we need not check that case either. + */ + ucmsg = (struct cmsghdr *) orig_cmsg_uptr; + while(((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { + struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; + int clen64, clen32; + + /* UCMSG is the 64-bit format CMSG entry in user-space. + * KCMSG32 is within the kernel space temporary buffer + * we use to convert into a 32-bit style CMSG. + */ + __get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); + __get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); + __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); + + clen64 = kcmsg32->cmsg_len; + copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), + clen64 - CMSG_ALIGN(sizeof(*ucmsg))); + clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + + CMSG32_ALIGN(sizeof(struct cmsghdr32))); + kcmsg32->cmsg_len = clen32; + + ucmsg = (struct cmsghdr *) (((char *)ucmsg) + + CMSG_ALIGN(clen64)); + wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); + } + + /* Copy back fixed up data, and adjust pointers. */ + bufsz = (wp - workbuf); + copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz); + + kmsg->msg_control = (struct cmsghdr *) + (((char *)orig_cmsg_uptr) + bufsz); + kmsg->msg_controllen = space_avail - bufsz; + + kfree(workbuf); + return; + +fail: + /* If we leave the 64-bit format CMSG chunks in there, + * the application could get confused and crash. So to + * ensure greater recovery, we report no CMSGs. + */ + kmsg->msg_controllen += bufsz; + kmsg->msg_control = (void *) orig_cmsg_uptr; +} + +asmlinkage int +sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) +{ + struct socket *sock; + char address[MAX_SOCK_ADDR]; + struct iovec iov[UIO_FASTIOV]; + unsigned char ctl[sizeof(struct cmsghdr) + 20]; + unsigned char *ctl_buf = ctl; + struct msghdr kern_msg; + int err, total_len; + + if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) + return -EFAULT; + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; + err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ); + if (err < 0) + goto out; + total_len = err; + + if(kern_msg.msg_controllen) { + err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl)); + if(err) + goto out_freeiov; + ctl_buf = kern_msg.msg_control; + } + kern_msg.msg_flags = user_flags; + + lock_kernel(); + sock = sockfd_lookup(fd, &err); + if (sock != NULL) { + if (sock->file->f_flags & O_NONBLOCK) + kern_msg.msg_flags |= MSG_DONTWAIT; + err = sock_sendmsg(sock, &kern_msg, total_len); + sockfd_put(sock); + } + unlock_kernel(); + + /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ + if(ctl_buf != ctl) + kfree(ctl_buf); +out_freeiov: + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); +out: + return err; +} + +asmlinkage int +sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags) +{ + struct iovec iovstack[UIO_FASTIOV]; + struct msghdr kern_msg; + char addr[MAX_SOCK_ADDR]; + struct socket *sock; + struct iovec *iov = iovstack; + struct sockaddr *uaddr; + int *uaddr_len; + unsigned long cmsg_ptr; + int err, total_len, len = 0; + + if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) + return -EFAULT; + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; + + uaddr = kern_msg.msg_name; + uaddr_len = &user_msg->msg_namelen; + err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); + if (err < 0) + goto out; + total_len = err; + + cmsg_ptr = (unsigned long) kern_msg.msg_control; + kern_msg.msg_flags = 0; + + lock_kernel(); + sock = sockfd_lookup(fd, &err); + if (sock != NULL) { + struct scm_cookie scm; + + if (sock->file->f_flags & O_NONBLOCK) + user_flags |= MSG_DONTWAIT; + memset(&scm, 0, sizeof(scm)); + err = sock->ops->recvmsg(sock, &kern_msg, total_len, + user_flags, &scm); + if(err >= 0) { + len = err; + if(!kern_msg.msg_control) { + if(sock->passcred || scm.fp) + kern_msg.msg_flags |= MSG_CTRUNC; + if(scm.fp) + __scm_destroy(&scm); + } else { + /* If recvmsg processing itself placed some + * control messages into user space, it's is + * using 64-bit CMSG processing, so we need + * to fix it up before we tack on more stuff. + */ + if((unsigned long) kern_msg.msg_control + != cmsg_ptr) + cmsg32_recvmsg_fixup(&kern_msg, + cmsg_ptr); + + /* Wheee... */ + if(sock->passcred) + put_cmsg32(&kern_msg, + SOL_SOCKET, SCM_CREDENTIALS, + sizeof(scm.creds), + &scm.creds); + if(scm.fp != NULL) + scm_detach_fds32(&kern_msg, &scm); + } + } + sockfd_put(sock); + } + unlock_kernel(); + + if(uaddr != NULL && err >= 0) + err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, + uaddr_len); + if(cmsg_ptr != 0 && err >= 0) { + unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); + __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr + - cmsg_ptr); + err |= __put_user(uclen, &user_msg->msg_controllen); + } + if(err >= 0) + err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); +out: + if(err < 0) + return err; + return len; +} + +extern void check_pending(int signum); + +asmlinkage int +sys32_sigaction (int sig, struct old_sigaction32 *act, + struct old_sigaction32 *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if(sig < 0) { + current->tss.new_signal = 1; + sig = -sig; + } + + if (act) { + old_sigset_t32 mask; + + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); + ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= __get_user(mask, &act->sa_mask); + if (ret) + return ret; + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); + ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +#ifdef CONFIG_MODULES + +extern asmlinkage unsigned long sys_create_module(const char *name_user, + size_t size); + +asmlinkage unsigned long +sys32_create_module(const char *name_user, __kernel_size_t32 size) +{ + return sys_create_module(name_user, (size_t)size); +} + +extern asmlinkage int sys_init_module(const char *name_user, + struct module *mod_user); + +/* Hey, when you're trying to init module, take time and prepare us a nice 64bit + * module structure, even if from 32bit modutils... Why to pollute kernel... :)) + */ +asmlinkage int +sys32_init_module(const char *name_user, struct module *mod_user) +{ + return sys_init_module(name_user, mod_user); +} + +extern asmlinkage int sys_delete_module(const char *name_user); + +asmlinkage int +sys32_delete_module(const char *name_user) +{ + return sys_delete_module(name_user); +} + +struct module_info32 { + u32 addr; + u32 size; + u32 flags; + s32 usecount; +}; + +/* Query various bits about modules. */ + +static inline long +get_mod_name(const char *user_name, char **buf) +{ + unsigned long page; + long retval; + + if ((unsigned long)user_name >= TASK_SIZE + && !segment_eq(get_fs (), KERNEL_DS)) + return -EFAULT; + + page = __get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE); + if (retval > 0) { + if (retval < PAGE_SIZE) { + *buf = (char *)page; + return retval; + } + retval = -ENAMETOOLONG; + } else if (!retval) + retval = -EINVAL; + + free_page(page); + return retval; +} + +static inline void +put_mod_name(char *buf) +{ + free_page((unsigned long)buf); +} + +static __inline__ struct module * +find_module(const char *name) +{ + struct module *mod; + + for (mod = module_list; mod ; mod = mod->next) { + if (mod->flags & MOD_DELETED) + continue; + if (!strcmp(mod->name, name)) + break; + } + + return mod; +} + +static int +qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + struct module *mod; + size_t nmod, space, len; + + nmod = space = 0; + + for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) { + len = strlen(mod->name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, mod->name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(nmod, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while ((mod = mod->next)->next != NULL) + space += strlen(mod->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static int +qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + size_t i, space, len; + + if (mod->next == NULL) + return -EINVAL; + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = 0; + for (i = 0; i < mod->ndeps; ++i) { + const char *dep_name = mod->deps[i].dep->name; + + len = strlen(dep_name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, dep_name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(i, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while (++i < mod->ndeps) + space += strlen(mod->deps[i].dep->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static int +qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + size_t nrefs, space, len; + struct module_ref *ref; + + if (mod->next == NULL) + return -EINVAL; + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = 0; + for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) { + const char *ref_name = ref->ref->name; + + len = strlen(ref_name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, ref_name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(nrefs, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while ((ref = ref->next_ref) != NULL) + space += strlen(ref->ref->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static inline int +qm_symbols(struct module *mod, char *buf, size_t bufsize, + __kernel_size_t32 *ret) +{ + size_t i, space, len; + struct module_symbol *s; + char *strings; + unsigned *vals; + + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = mod->nsyms * 2*sizeof(u32); + + i = len = 0; + s = mod->syms; + + if (space > bufsize) + goto calc_space_needed; + + if (!access_ok(VERIFY_WRITE, buf, space)) + return -EFAULT; + + bufsize -= space; + vals = (unsigned *)buf; + strings = buf+space; + + for (; i < mod->nsyms ; ++i, ++s, vals += 2) { + len = strlen(s->name)+1; + if (len > bufsize) + goto calc_space_needed; + + if (copy_to_user(strings, s->name, len) + || __put_user(s->value, vals+0) + || __put_user(space, vals+1)) + return -EFAULT; + + strings += len; + bufsize -= len; + space += len; + } + + if (put_user(i, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + for (; i < mod->nsyms; ++i, ++s) + space += strlen(s->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static inline int +qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + int error = 0; + + if (mod->next == NULL) + return -EINVAL; + + if (sizeof(struct module_info32) <= bufsize) { + struct module_info32 info; + info.addr = (unsigned long)mod; + info.size = mod->size; + info.flags = mod->flags; + info.usecount = + ((mod_member_present(mod, can_unload) + && mod->can_unload) + ? -1 : atomic_read(&mod->uc.usecount)); + + if (copy_to_user(buf, &info, sizeof(struct module_info32))) + return -EFAULT; + } else + error = -ENOSPC; + + if (put_user(sizeof(struct module_info32), ret)) + return -EFAULT; + + return error; +} + +asmlinkage int +sys32_query_module(char *name_user, int which, char *buf, + __kernel_size_t32 bufsize, u32 ret) +{ + struct module *mod; + int err; + + lock_kernel(); + if (name_user == 0) { + /* This finds "kernel_module" which is not exported. */ + for(mod = module_list; mod->next != NULL; mod = mod->next) + ; + } else { + long namelen; + char *name; + + if ((namelen = get_mod_name(name_user, &name)) < 0) { + err = namelen; + goto out; + } + err = -ENOENT; + if (namelen == 0) { + /* This finds "kernel_module" which is not exported. */ + for(mod = module_list; + mod->next != NULL; + mod = mod->next) ; + } else if ((mod = find_module(name)) == NULL) { + put_mod_name(name); + goto out; + } + put_mod_name(name); + } + + switch (which) + { + case 0: + err = 0; + break; + case QM_MODULES: + err = qm_modules(buf, bufsize, (__kernel_size_t32 *)AA(ret)); + break; + case QM_DEPS: + err = qm_deps(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); + break; + case QM_REFS: + err = qm_refs(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); + break; + case QM_SYMBOLS: + err = qm_symbols(mod, buf, bufsize, + (__kernel_size_t32 *)AA(ret)); + break; + case QM_INFO: + err = qm_info(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); + break; + default: + err = -EINVAL; + break; + } +out: + unlock_kernel(); + return err; +} + +struct kernel_sym32 { + u32 value; + char name[60]; +}; + +extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table); + +asmlinkage int +sys32_get_kernel_syms(struct kernel_sym32 *table) +{ + int len, i; + struct kernel_sym *tbl; + mm_segment_t old_fs; + + len = sys_get_kernel_syms(NULL); + if (!table) return len; + tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL); + if (!tbl) return -ENOMEM; + old_fs = get_fs(); + set_fs (KERNEL_DS); + sys_get_kernel_syms(tbl); + set_fs (old_fs); + for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) { + if (put_user (tbl[i].value, &table->value) || + copy_to_user (table->name, tbl[i].name, 60)) + break; + } + kfree (tbl); + return i; +} + +#else /* CONFIG_MODULES */ + +asmlinkage unsigned long +sys32_create_module(const char *name_user, size_t size) +{ + return -ENOSYS; +} + +asmlinkage int +sys32_init_module(const char *name_user, struct module *mod_user) +{ + return -ENOSYS; +} + +asmlinkage int +sys32_delete_module(const char *name_user) +{ + return -ENOSYS; +} + +asmlinkage int +sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize, + size_t *ret) +{ + /* Let the program know about the new interface. Not that + it'll do them much good. */ + if (which == 0) + return 0; + + return -ENOSYS; +} + +asmlinkage int +sys32_get_kernel_syms(struct kernel_sym *table) +{ + return -ENOSYS; +} + +#endif /* CONFIG_MODULES */ + +/* Stuff for NFS server syscalls... */ +struct nfsctl_svc32 { + u16 svc32_port; + s32 svc32_nthreads; +}; + +struct nfsctl_client32 { + s8 cl32_ident[NFSCLNT_IDMAX+1]; + s32 cl32_naddr; + struct in_addr cl32_addrlist[NFSCLNT_ADDRMAX]; + s32 cl32_fhkeytype; + s32 cl32_fhkeylen; + u8 cl32_fhkey[NFSCLNT_KEYMAX]; +}; + +struct nfsctl_export32 { + s8 ex32_client[NFSCLNT_IDMAX+1]; + s8 ex32_path[NFS_MAXPATHLEN+1]; + __kernel_dev_t32 ex32_dev; + __kernel_ino_t32 ex32_ino; + s32 ex32_flags; + __kernel_uid_t32 ex32_anon_uid; + __kernel_gid_t32 ex32_anon_gid; +}; + +struct nfsctl_uidmap32 { + u32 ug32_ident; /* char * */ + __kernel_uid_t32 ug32_uidbase; + s32 ug32_uidlen; + u32 ug32_udimap; /* uid_t * */ + __kernel_uid_t32 ug32_gidbase; + s32 ug32_gidlen; + u32 ug32_gdimap; /* gid_t * */ +}; + +struct nfsctl_fhparm32 { + struct sockaddr gf32_addr; + __kernel_dev_t32 gf32_dev; + __kernel_ino_t32 gf32_ino; + s32 gf32_version; +}; + +struct nfsctl_arg32 { + s32 ca32_version; /* safeguard */ + union { + struct nfsctl_svc32 u32_svc; + struct nfsctl_client32 u32_client; + struct nfsctl_export32 u32_export; + struct nfsctl_uidmap32 u32_umap; + struct nfsctl_fhparm32 u32_getfh; + u32 u32_debug; + } u; +#define ca32_svc u.u32_svc +#define ca32_client u.u32_client +#define ca32_export u.u32_export +#define ca32_umap u.u32_umap +#define ca32_getfh u.u32_getfh +#define ca32_authd u.u32_authd +#define ca32_debug u.u32_debug +}; + +union nfsctl_res32 { + struct knfs_fh cr32_getfh; + u32 cr32_debug; +}; + +static int +nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) +{ + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port); + err |= __get_user(karg->ca_svc.svc_nthreads, + &arg32->ca32_svc.svc32_nthreads); + return err; +} + +static int +nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) +{ + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_client.cl_ident[0], + &arg32->ca32_client.cl32_ident[0], + NFSCLNT_IDMAX); + err |= __get_user(karg->ca_client.cl_naddr, + &arg32->ca32_client.cl32_naddr); + err |= copy_from_user(&karg->ca_client.cl_addrlist[0], + &arg32->ca32_client.cl32_addrlist[0], + (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)); + err |= __get_user(karg->ca_client.cl_fhkeytype, + &arg32->ca32_client.cl32_fhkeytype); + err |= __get_user(karg->ca_client.cl_fhkeylen, + &arg32->ca32_client.cl32_fhkeylen); + err |= copy_from_user(&karg->ca_client.cl_fhkey[0], + &arg32->ca32_client.cl32_fhkey[0], + NFSCLNT_KEYMAX); + return err; +} + +static int +nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) +{ + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_export.ex_client[0], + &arg32->ca32_export.ex32_client[0], + NFSCLNT_IDMAX); + err |= copy_from_user(&karg->ca_export.ex_path[0], + &arg32->ca32_export.ex32_path[0], + NFS_MAXPATHLEN); + err |= __get_user(karg->ca_export.ex_dev, + &arg32->ca32_export.ex32_dev); + err |= __get_user(karg->ca_export.ex_ino, + &arg32->ca32_export.ex32_ino); + err |= __get_user(karg->ca_export.ex_flags, + &arg32->ca32_export.ex32_flags); + err |= __get_user(karg->ca_export.ex_anon_uid, + &arg32->ca32_export.ex32_anon_uid); + err |= __get_user(karg->ca_export.ex_anon_gid, + &arg32->ca32_export.ex32_anon_gid); + return err; +} + +static int +nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) +{ + u32 uaddr; + int i; + int err; + + memset(karg, 0, sizeof(*karg)); + if(__get_user(karg->ca_version, &arg32->ca32_version)) + return -EFAULT; + karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER); + if(!karg->ca_umap.ug_ident) + return -ENOMEM; + err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident); + if(strncpy_from_user(karg->ca_umap.ug_ident, + (char *)A(uaddr), PAGE_SIZE) <= 0) + return -EFAULT; + err |= __get_user(karg->ca_umap.ug_uidbase, + &arg32->ca32_umap.ug32_uidbase); + err |= __get_user(karg->ca_umap.ug_uidlen, + &arg32->ca32_umap.ug32_uidlen); + err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap); + if (err) + return -EFAULT; + karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * + karg->ca_umap.ug_uidlen), + GFP_USER); + if(!karg->ca_umap.ug_udimap) + return -ENOMEM; + for(i = 0; i < karg->ca_umap.ug_uidlen; i++) + err |= __get_user(karg->ca_umap.ug_udimap[i], + &(((__kernel_uid_t32 *)A(uaddr))[i])); + err |= __get_user(karg->ca_umap.ug_gidbase, + &arg32->ca32_umap.ug32_gidbase); + err |= __get_user(karg->ca_umap.ug_uidlen, + &arg32->ca32_umap.ug32_gidlen); + err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap); + if (err) + return -EFAULT; + karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * + karg->ca_umap.ug_uidlen), + GFP_USER); + if(!karg->ca_umap.ug_gdimap) + return -ENOMEM; + for(i = 0; i < karg->ca_umap.ug_gidlen; i++) + err |= __get_user(karg->ca_umap.ug_gdimap[i], + &(((__kernel_gid_t32 *)A(uaddr))[i])); + + return err; +} + +static int +nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) +{ + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_getfh.gf_addr, + &arg32->ca32_getfh.gf32_addr, + (sizeof(struct sockaddr))); + err |= __get_user(karg->ca_getfh.gf_dev, + &arg32->ca32_getfh.gf32_dev); + err |= __get_user(karg->ca_getfh.gf_ino, + &arg32->ca32_getfh.gf32_ino); + err |= __get_user(karg->ca_getfh.gf_version, + &arg32->ca32_getfh.gf32_version); + return err; +} + +static int +nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32) +{ + int err; + + err = copy_to_user(&res32->cr32_getfh, + &kres->cr_getfh, + sizeof(res32->cr32_getfh)); + err |= __put_user(kres->cr_debug, &res32->cr32_debug); + return err; +} + +extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp); + +int asmlinkage +sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32) +{ + struct nfsctl_arg *karg = NULL; + union nfsctl_res *kres = NULL; + mm_segment_t oldfs; + int err; + + karg = kmalloc(sizeof(*karg), GFP_USER); + if(!karg) + return -ENOMEM; + if(res32) { + kres = kmalloc(sizeof(*kres), GFP_USER); + if(!kres) { + kfree(karg); + return -ENOMEM; + } + } + switch(cmd) { + case NFSCTL_SVC: + err = nfs_svc32_trans(karg, arg32); + break; + case NFSCTL_ADDCLIENT: + err = nfs_clnt32_trans(karg, arg32); + break; + case NFSCTL_DELCLIENT: + err = nfs_clnt32_trans(karg, arg32); + break; + case NFSCTL_EXPORT: + err = nfs_exp32_trans(karg, arg32); + break; + /* This one is unimplemented, be we're ready for it. */ + case NFSCTL_UGIDUPDATE: + err = nfs_uud32_trans(karg, arg32); + break; + case NFSCTL_GETFH: + err = nfs_getfh32_trans(karg, arg32); + break; + default: + err = -EINVAL; + break; + } + if(err) + goto done; + oldfs = get_fs(); + set_fs(KERNEL_DS); + err = sys_nfsservctl(cmd, karg, kres); + set_fs(oldfs); + + if(!err && cmd == NFSCTL_GETFH) + err = nfs_getfh32_res_trans(kres, res32); + +done: + if(karg) { + if(cmd == NFSCTL_UGIDUPDATE) { + if(karg->ca_umap.ug_ident) + kfree(karg->ca_umap.ug_ident); + if(karg->ca_umap.ug_udimap) + kfree(karg->ca_umap.ug_udimap); + if(karg->ca_umap.ug_gdimap) + kfree(karg->ca_umap.ug_gdimap); + } + kfree(karg); + } + if(kres) + kfree(kres); + return err; +} + +asmlinkage int sys_utimes(char *, struct timeval *); + +asmlinkage int +sys32_utimes(char *filename, struct timeval32 *tvs) +{ + char *kfilename; + struct timeval ktvs[2]; + mm_segment_t old_fs; + int ret; + + kfilename = getname32(filename); + ret = PTR_ERR(kfilename); + if (!IS_ERR(kfilename)) { + if (tvs) { + if (get_tv32(&ktvs[0], tvs) || + get_tv32(&ktvs[1], 1+tvs)) + return -EFAULT; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_utimes(kfilename, &ktvs[0]); + set_fs(old_fs); + + putname(kfilename); + } + return ret; +} + +/* These are here just in case some old ia32 binary calls it. */ +asmlinkage int +sys32_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + +/* PCI config space poking. */ +extern asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf); + +extern asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf); + +asmlinkage int +sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +{ + return sys_pciconfig_read((unsigned long) bus, + (unsigned long) dfn, + (unsigned long) off, + (unsigned long) len, + (unsigned char *)AA(ubuf)); +} + +asmlinkage int +sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) +{ + return sys_pciconfig_write((unsigned long) bus, + (unsigned long) dfn, + (unsigned long) off, + (unsigned long) len, + (unsigned char *)AA(ubuf)); +} + +extern asmlinkage int sys_prctl(int option, unsigned long arg2, + unsigned long arg3, unsigned long arg4, + unsigned long arg5); + +asmlinkage int +sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) +{ + return sys_prctl(option, + (unsigned long) arg2, + (unsigned long) arg3, + (unsigned long) arg4, + (unsigned long) arg5); +} + + +extern asmlinkage int sys_newuname(struct new_utsname * name); + +asmlinkage int +sys32_newuname(struct new_utsname * name) +{ + int ret = sys_newuname(name); + + if (current->personality == PER_LINUX32 && !ret) { + ret = copy_to_user(name->machine, "sparc\0\0", 8); + } + return ret; +} + +extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf, + size_t count, loff_t pos); + +extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf, + size_t count, loff_t pos); + +typedef __kernel_ssize_t32 ssize_t32; + +asmlinkage ssize_t32 +sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count, + u32 poshi, u32 poslo) +{ + return sys_pread(fd, ubuf, count, + ((loff_t)AA(poshi) << 32) | AA(poslo)); +} + +asmlinkage ssize_t32 +sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count, + u32 poshi, u32 poslo) +{ + return sys_pwrite(fd, ubuf, count, + ((loff_t)AA(poshi) << 32) | AA(poslo)); +} + + +extern asmlinkage int sys_personality(unsigned long); + +asmlinkage int +sys32_personality(unsigned long personality) +{ + int ret; + lock_kernel(); + if (current->personality == PER_LINUX32 && personality == PER_LINUX) + personality = PER_LINUX32; + ret = sys_personality(personality); + unlock_kernel(); + if (ret == PER_LINUX32) + ret = PER_LINUX; + return ret; +} + +extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, + size_t count); + +asmlinkage int +sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) +{ + mm_segment_t old_fs = get_fs(); + int ret; + off_t of; + + if (offset && get_user(of, offset)) + return -EFAULT; + + set_fs(KERNEL_DS); + ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); + set_fs(old_fs); + + if (!ret && offset && put_user(of, offset)) + return -EFAULT; + + return ret; +} + +/* Handle adjtimex compatability. */ + +struct timex32 { + u32 modes; + s32 offset, freq, maxerror, esterror; + s32 status, constant, precision, tolerance; + struct timeval32 time; + s32 tick; + s32 ppsfreq, jitter, shift, stabil; + s32 jitcnt, calcnt, errcnt, stbcnt; + s32 :32; s32 :32; s32 :32; s32 :32; + s32 :32; s32 :32; s32 :32; s32 :32; + s32 :32; s32 :32; s32 :32; s32 :32; +}; + +extern int do_adjtimex(struct timex *); + +asmlinkage int +sys32_adjtimex(struct timex32 *utp) +{ + struct timex txc; + int ret; + + memset(&txc, 0, sizeof(struct timex)); + + if(get_user(txc.modes, &utp->modes) || + __get_user(txc.offset, &utp->offset) || + __get_user(txc.freq, &utp->freq) || + __get_user(txc.maxerror, &utp->maxerror) || + __get_user(txc.esterror, &utp->esterror) || + __get_user(txc.status, &utp->status) || + __get_user(txc.constant, &utp->constant) || + __get_user(txc.precision, &utp->precision) || + __get_user(txc.tolerance, &utp->tolerance) || + __get_user(txc.time.tv_sec, &utp->time.tv_sec) || + __get_user(txc.time.tv_usec, &utp->time.tv_usec) || + __get_user(txc.tick, &utp->tick) || + __get_user(txc.ppsfreq, &utp->ppsfreq) || + __get_user(txc.jitter, &utp->jitter) || + __get_user(txc.shift, &utp->shift) || + __get_user(txc.stabil, &utp->stabil) || + __get_user(txc.jitcnt, &utp->jitcnt) || + __get_user(txc.calcnt, &utp->calcnt) || + __get_user(txc.errcnt, &utp->errcnt) || + __get_user(txc.stbcnt, &utp->stbcnt)) + return -EFAULT; + + ret = do_adjtimex(&txc); + + if(put_user(txc.modes, &utp->modes) || + __put_user(txc.offset, &utp->offset) || + __put_user(txc.freq, &utp->freq) || + __put_user(txc.maxerror, &utp->maxerror) || + __put_user(txc.esterror, &utp->esterror) || + __put_user(txc.status, &utp->status) || + __put_user(txc.constant, &utp->constant) || + __put_user(txc.precision, &utp->precision) || + __put_user(txc.tolerance, &utp->tolerance) || + __put_user(txc.time.tv_sec, &utp->time.tv_sec) || + __put_user(txc.time.tv_usec, &utp->time.tv_usec) || + __put_user(txc.tick, &utp->tick) || + __put_user(txc.ppsfreq, &utp->ppsfreq) || + __put_user(txc.jitter, &utp->jitter) || + __put_user(txc.shift, &utp->shift) || + __put_user(txc.stabil, &utp->stabil) || + __put_user(txc.jitcnt, &utp->jitcnt) || + __put_user(txc.calcnt, &utp->calcnt) || + __put_user(txc.errcnt, &utp->errcnt) || + __put_user(txc.stbcnt, &utp->stbcnt)) + ret = -EFAULT; + + return ret; +} +#endif // NOTYET + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kdb/Makefile linux/arch/ia64/kdb/Makefile --- v2.3.42/linux/arch/ia64/kdb/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kdb/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,21 @@ +# +# Makefile for ia64-specific kdb files.. +# +# Copyright 1999, Silicon Graphics Inc. +# +# Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. +# Code for IA64 written by Goutham Rao and +# Sreenivas Subramoney +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o + +L_TARGET = kdb.a +L_OBJS = kdbsupport.o kdb_io.o kdb_bt.o kdb_traps.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kdb/kdb_bt.c linux/arch/ia64/kdb/kdb_bt.c --- v2.3.42/linux/arch/ia64/kdb/kdb_bt.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kdb/kdb_bt.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,104 @@ +/** + * Minimalist Kernel Debugger + * Machine dependent stack traceback code for IA-64. + * + * Copyright (C) 1999 Goutham Rao + * Copyright (C) 1999 Sreenivas Subramoney + * Intel Corporation, August 1999. + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + * + * 99/12/03 D. Mosberger Reimplemented based on API. + * 99/12/06 D. Mosberger Added support for backtracing other processes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Minimal stack back trace functionality. + */ +int +kdb_bt (int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct task_struct *task = current; + struct ia64_frame_info info; + char *name; + int diag; + + if (strcmp(argv[0], "btp") == 0) { + unsigned long pid; + + diag = kdbgetularg(argv[1], &pid); + if (diag) + return diag; + + task = find_task_by_pid(pid); + if (!task) { + kdb_printf("No process with pid == %d found\n", pid); + return 0; + } + regs = ia64_task_regs(task); + } else if (argc) { + kdb_printf("bt
is unsupported for IA-64\n"); + return 0; + } + + if (task == current) { + /* + * Upon entering kdb, the stack frame looks like this: + * + * +---------------------+ + * | struct pt_regs | + * +---------------------+ + * | | + * | kernel stack | + * | | + * +=====================+ <--- top of stack upon entering kdb + * | struct pt_regs | + * +---------------------+ + * | struct switch_stack | + * +---------------------+ + */ + if (user_mode(regs)) { + /* We are not implementing stack backtrace from user mode code */ + kdb_printf ("Not in Kernel\n"); + return 0; + } + ia64_unwind_init_from_current(&info, regs); + } else { + /* + * For a blocked task, the stack frame looks like this: + * + * +---------------------+ + * | struct pt_regs | + * +---------------------+ + * | | + * | kernel stack | + * | | + * +---------------------+ + * | struct switch_stack | + * +=====================+ <--- task->thread.ksp + */ + ia64_unwind_init_from_blocked_task(&info, task); + } + + kdb_printf("Ret Address Reg Stack base Name\n\n") ; + do { + unsigned long ip = ia64_unwind_get_ip(&info); + + name = kdbnearsym(ip); + if (!name) { + kdb_printf("Interrupt\n"); + return 0; + } + kdb_printf("0x%016lx: [0x%016lx] %s\n", ip, ia64_unwind_get_bsp(&info), name); + } while (ia64_unwind_to_previous_frame(&info) >= 0); + return 0; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kdb/kdb_io.c linux/arch/ia64/kdb/kdb_io.c --- v2.3.42/linux/arch/ia64/kdb/kdb_io.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kdb/kdb_io.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,350 @@ +/* + * Kernel Debugger Console I/O handler + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Chuck Fleckenstein 1999/07/20 + * Move kdb_info struct declaration to this file + * for cases where serial support is not compiled into + * the kernel. + * + * Masahiro Adegawa 1999/07/20 + * Handle some peculiarities of japanese 86/106 + * keyboards. + * + * marc@mucom.co.il 1999/07/20 + * Catch buffer overflow for serial input. + * + * Scott Foehner + * Port to ia64 + */ + +#include +#include +#include +#include +#include + +#include + +#include "pc_keyb.h" + +int kdb_port = 0; + +/* + * This module contains code to read characters from the keyboard or a serial + * port. + * + * It is used by the kernel debugger, and is polled, not interrupt driven. + * + */ + +/* + * send: Send a byte to the keyboard controller. Used primarily to + * alter LED settings. + */ + +static void +kdb_kbdsend(unsigned char byte) +{ + while (inb(KBD_STATUS_REG) & KBD_STAT_IBF) + ; + outb(KBD_DATA_REG, byte); +} + +static void +kdb_kbdsetled(int leds) +{ + kdb_kbdsend(KBD_CMD_SET_LEDS); + kdb_kbdsend((unsigned char)leds); +} + +static void +console_read (char *buffer, size_t bufsize) +{ + struct console *in; + struct console *out; + char *cp, ch; + + for (in = console_drivers; in; in = in->next) { + if ((in->flags & CON_ENABLED) && (in->read || in->wait_key)) + break; + } + for (out = console_drivers; out; out = out->next) { + if ((out->flags & CON_ENABLED) && out->write) + break; + } + + if ((!in->read && !in->wait_key) || !out->write) { + panic("kdb_io: can't do console i/o!"); + } + + if (in->read) { + /* this is untested... */ + (*in->read)(in, buffer, bufsize); + return; + } + + bufsize -= 2; /* leave room for CR & NUL terminator */ + cp = buffer; + while (1) { + ch = (*in->wait_key)(in); + switch (ch) { + case '\b': + if (cp > buffer) { + --cp, ++bufsize; + (*out->write)(out, "\b \b", 3); + } + break; + + case '\025': + while (cp > buffer) { + --cp, ++bufsize; + (*out->write)(out, "\b \b", 3); + } + break; + + case '\r': + case '\n': + (*out->write)(out, "\r\n", 2); + *cp++ = '\n'; + *cp++ = '\0'; + return; + + default: + if (bufsize > 0) { + (*out->write)(out, &ch, 1); + --bufsize; + *cp++ = ch; + } + break; + } + } +} + +char * +kdb_getscancode(char *buffer, size_t bufsize) +{ + /* + * XXX Shouldn't kdb _always_ use console based I/O? That's what the console + * abstraction is for, after all... ---davidm + */ +#ifdef CONFIG_IA64_HP_SIM + extern spinlock_t console_lock; + unsigned long flags; + + spin_lock_irqsave(&console_lock, flags); + console_read(buffer, bufsize); + spin_unlock_irqrestore(&console_lock, flags); + return buffer; +#else /* !CONFIG_IA64_HP_SIM */ + char *cp = buffer; + int scancode, scanstatus; + static int shift_lock = 0; /* CAPS LOCK state (0-off, 1-on) */ + static int shift_key = 0; /* Shift next keypress */ + static int ctrl_key = 0; + static int leds = 2; /* Num lock */ + u_short keychar; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + bufsize -= 2; /* Reserve space for newline and null byte */ + + /* + * If we came in via a serial console, we allow that to + * be the input window for kdb. + */ + if (kdb_port != 0) { + char ch; + int status; +#define serial_inp(info, offset) inb((info) + (offset)) +#define serial_out(info, offset, v) outb((v), (info) + (offset)) + + while(1) { + while ((status = serial_inp(kdb_port, UART_LSR)) + & UART_LSR_DR) { +readchar: + ch = serial_inp(kdb_port, UART_RX); + if (ch == 8) { /* BS */ + if (cp > buffer) { + --cp, bufsize++; + printk("%c %c", 0x08, 0x08); + } + continue; + } + serial_out(kdb_port, UART_TX, ch); + if (ch == 13) { /* CR */ + *cp++ = '\n'; + *cp++ = '\0'; + serial_out(kdb_port, UART_TX, 10); + return(buffer); + } + /* + * Discard excess characters + */ + if (bufsize > 0) { + *cp++ = ch; + bufsize--; + } + } + while (((status = serial_inp(kdb_port, UART_LSR)) + & UART_LSR_DR) == 0); + } + } + + while (1) { + + /* + * Wait for a valid scancode + */ + + while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + ; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + /* + * Ignore mouse events. + */ + if (scanstatus & KBD_STAT_MOUSE_OBF) + continue; + + /* + * Ignore release, trigger on make + * (except for shift keys, where we want to + * keep the shift state so long as the key is + * held down). + */ + + if (((scancode&0x7f) == 0x2a) + || ((scancode&0x7f) == 0x36)) { + /* + * Next key may use shift table + */ + if ((scancode & 0x80) == 0) { + shift_key=1; + } else { + shift_key=0; + } + continue; + } + + if ((scancode&0x7f) == 0x1d) { + /* + * Left ctrl key + */ + if ((scancode & 0x80) == 0) { + ctrl_key = 1; + } else { + ctrl_key = 0; + } + continue; + } + + if ((scancode & 0x80) != 0) + continue; + + scancode &= 0x7f; + + /* + * Translate scancode + */ + + if (scancode == 0x3a) { + /* + * Toggle caps lock + */ + shift_lock ^= 1; + leds ^= 0x4; /* toggle caps lock led */ + + kdb_kbdsetled(leds); + continue; + } + + if (scancode == 0x0e) { + /* + * Backspace + */ + if (cp > buffer) { + --cp, bufsize++; + + /* + * XXX - erase character on screen + */ + printk("%c %c", 0x08, 0x08); + } + continue; + } + + if (scancode == 0xe0) { + continue; + } + + /* + * For Japanese 86/106 keyboards + * See comment in drivers/char/pc_keyb.c. + * - Masahiro Adegawa + */ + if (scancode == 0x73) { + scancode = 0x59; + } else if (scancode == 0x7d) { + scancode = 0x7c; + } + + if (!shift_lock && !shift_key) { + keychar = plain_map[scancode]; + } else if (shift_lock || shift_key) { + keychar = shift_map[scancode]; + } else if (ctrl_key) { + keychar = ctrl_map[scancode]; + } else { + keychar = 0x0020; + printk("Unknown state/scancode (%d)\n", scancode); + } + + if ((scancode & 0x7f) == 0x1c) { + /* + * enter key. All done. + */ + printk("\n"); + break; + } + + /* + * echo the character. + */ + printk("%c", keychar&0xff); + + if (bufsize) { + --bufsize; + *cp++ = keychar&0xff; + } else { + printk("buffer overflow\n"); + break; + } + + } + + *cp++ = '\n'; /* White space for parser */ + *cp++ = '\0'; /* String termination */ + +#if defined(NOTNOW) + cp = buffer; + while (*cp) { + printk("char 0x%x\n", *cp++); + } +#endif + + return buffer; +#endif /* !CONFIG_IA64_HP_SIM */ +} + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kdb/kdb_traps.c linux/arch/ia64/kdb/kdb_traps.c --- v2.3.42/linux/arch/ia64/kdb/kdb_traps.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kdb/kdb_traps.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +static struct kdb_bp_support { + unsigned long addr ; + int slot ; +} kdb_bp_info[NR_CPUS] ; + + +extern void kdb_bp_install (void); + +/* + * This gets invoked right before a call to ia64_fault(). + * Returns zero the normal fault handler should be invoked. + */ +long +ia64_kdb_fault_handler (unsigned long vector, unsigned long isr, unsigned long ifa, + unsigned long iim, unsigned long itir, unsigned long arg5, + unsigned long arg6, unsigned long arg7, unsigned long stack) +{ + struct switch_stack *sw = (struct switch_stack *) &stack; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + int bundle_slot; + + /* + * TBD + * If KDB is configured, enter KDB for any fault. + */ + if ((vector == 29) || (vector == 35) || (vector == 36)) { + if (!user_mode(regs)) { + bundle_slot = ia64_psr(regs)->ri; + if (vector == 29) { + if (bundle_slot == 0) { + kdb_bp_info[0].addr = regs->cr_iip; + kdb_bp_info[0].slot = bundle_slot; + kdb(KDB_REASON_FLTDBG, 0, regs); + } else { + if ((bundle_slot < 3) && + (kdb_bp_info[0].addr == regs->cr_iip)) + { + ia64_psr(regs)->id = 1; + ia64_psr(regs)->db = 1; + kdb_bp_install() ; + } else /* some error ?? */ + kdb(KDB_REASON_FLTDBG, 0, regs); + } + } else /* single step or taken branch */ + kdb(KDB_REASON_DEBUG, 0, regs); + return 1; + } + } + return 0; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kdb/kdbsupport.c linux/arch/ia64/kdb/kdbsupport.c --- v2.3.42/linux/arch/ia64/kdb/kdbsupport.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kdb/kdbsupport.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,1310 @@ +/* + * Minimalist Kernel Debugger + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * Copyright (C) David Mosberger-Tang + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Srinivasa Thirumalachar + * RSE support for ia64 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +extern kdb_state_t kdb_state ; +k_machreg_t dbregs[KDB_DBREGS]; + +static int __init +kdb_setup (char *str) +{ + kdb_flags |= KDB_FLAG_EARLYKDB; + return 1; +} + +__setup("kdb", kdb_setup); + +static int +kdb_ia64_sir (int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + u64 lid, tpr, lrr0, lrr1, itv, pmv, cmcv; + + asm ("mov %0=cr.lid" : "=r"(lid)); + asm ("mov %0=cr.tpr" : "=r"(tpr)); + asm ("mov %0=cr.lrr0" : "=r"(lrr0)); + asm ("mov %0=cr.lrr1" : "=r"(lrr1)); + printk ("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1); + + asm ("mov %0=cr.itv" : "=r"(itv)); + asm ("mov %0=cr.pmv" : "=r"(pmv)); + asm ("mov %0=cr.cmcv" : "=r"(cmcv)); + printk ("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv); + + printk ("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n", + ia64_get_irr0(), ia64_get_irr1(), ia64_get_irr2(), ia64_get_irr3()); + return 0; +} + +void __init +kdb_init (void) +{ + extern void kdb_inittab(void); + unsigned long reg; + + kdb_inittab(); + kdb_initbptab(); +#if 0 + kdb_disinit(); +#endif + kdb_printf("kdb version %d.%d by Scott Lurndal. "\ + "Copyright SGI, All Rights Reserved\n", + KDB_MAJOR_VERSION, KDB_MINOR_VERSION); + + /* Enable debug registers */ + __asm__ ("mov %0=psr":"=r"(reg)); + reg |= IA64_PSR_DB; + __asm__ ("mov psr.l=%0"::"r"(reg)); + ia64_srlz_d(); + + /* Init kdb state */ + kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ; + + kdb_register("irr", kdb_ia64_sir, "", "Show interrupt registers", 0); +} + +/* + * kdbprintf + * kdbgetword + * kdb_getstr + */ + +char * +kbd_getstr(char *buffer, size_t bufsize, char *prompt) +{ + extern char* kdb_getscancode(char *, size_t); + +#if defined(CONFIG_SMP) + kdb_printf(prompt, smp_processor_id()); +#else + kdb_printf("%s", prompt); +#endif + + return kdb_getscancode(buffer, bufsize); + +} + +int +kdb_printf(const char *fmt, ...) +{ + char buffer[256]; + va_list ap; + int diag; + int linecount; + + diag = kdbgetintenv("LINES", &linecount); + if (diag) + linecount = 22; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + + printk("%s", buffer); +#if 0 + if (strchr(buffer, '\n') != NULL) { + kdb_nextline++; + } + + if (kdb_nextline == linecount) { + char buf1[16]; + char buf2[32]; + extern char* kdb_getscancode(char *, size_t); + char *moreprompt; + + /* + * Pause until cr. + */ + moreprompt = kdbgetenv("MOREPROMPT"); + if (moreprompt == NULL) { + moreprompt = "more> "; + } + +#if defined(CONFIG_SMP) + if (strchr(moreprompt, '%')) { + sprintf(buf2, moreprompt, smp_processor_id()); + moreprompt = buf2; + } +#endif + + printk(moreprompt); + (void) kdb_getscancode(buf1, sizeof(buf1)); + + kdb_nextline = 1; + + if ((buf1[0] == 'q') + || (buf1[0] == 'Q')) { + kdb_longjmp(&kdbjmpbuf, 1); + } + } +#endif + return 0; +} + +unsigned long +kdbgetword(unsigned long addr, int width) +{ + /* + * This function checks the address for validity. Any address + * in the range PAGE_OFFSET to high_memory is legal, any address + * which maps to a vmalloc region is legal, and any address which + * is a user address, we use get_user() to verify validity. + */ + + if (addr < PAGE_OFFSET) { + /* + * Usermode address. + */ + unsigned long diag; + unsigned long ulval; + + switch (width) { + case 8: + { unsigned long *lp; + + lp = (unsigned long *) addr; + diag = get_user(ulval, lp); + break; + } + case 4: + { unsigned int *ip; + + ip = (unsigned int *) addr; + diag = get_user(ulval, ip); + break; + } + case 2: + { unsigned short *sp; + + sp = (unsigned short *) addr; + diag = get_user(ulval, sp); + break; + } + case 1: + { unsigned char *cp; + + cp = (unsigned char *) addr; + diag = get_user(ulval, cp); + break; + } + default: + printk("kdbgetword: Bad width\n"); + return 0L; + } + + if (diag) { + if ((kdb_flags & KDB_FLAG_SUPRESS) == 0) { + printk("kdb: Bad user address 0x%lx\n", addr); + kdb_flags |= KDB_FLAG_SUPRESS; + } + return 0L; + } + kdb_flags &= ~KDB_FLAG_SUPRESS; + return ulval; + } + + if (addr > (unsigned long)high_memory) { + extern int kdb_vmlist_check(unsigned long, unsigned long); + + if (!kdb_vmlist_check(addr, addr+width)) { + /* + * Would appear to be an illegal kernel address; + * Print a message once, and don't print again until + * a legal address is used. + */ + if ((kdb_flags & KDB_FLAG_SUPRESS) == 0) { + printk("kdb: Bad kernel address 0x%lx\n", addr); + kdb_flags |= KDB_FLAG_SUPRESS; + } + return 0L; + } + } + + /* + * A good address. Reset error flag. + */ + kdb_flags &= ~KDB_FLAG_SUPRESS; + + switch (width) { + case 8: + { unsigned long *lp; + + lp = (unsigned long *)(addr); + return *lp; + } + case 4: + { unsigned int *ip; + + ip = (unsigned int *)(addr); + return *ip; + } + case 2: + { unsigned short *sp; + + sp = (unsigned short *)(addr); + return *sp; + } + case 1: + { unsigned char *cp; + + cp = (unsigned char *)(addr); + return *cp; + } + } + + printk("kdbgetword: Bad width\n"); + return 0L; +} + +/* + * Start of breakpoint management routines + */ + +/* + * Arg: bp structure + */ + +int +kdb_allocdbreg(kdb_bp_t *bp) +{ + int i=0; + + /* For inst bkpt, just return. No hw reg alloc to be done. */ + + if (bp->bp_mode == BKPTMODE_INST) { + return i; + } else if (bp->bp_mode == BKPTMODE_DATAW) { + for(i=0; ibp_mode == BKPTMODE_DATAW) + dbregs[bp->bp_reg] = 0xffffffff; +} + +void +kdb_initdbregs(void) +{ + int i; + + for(i=0; ibp_addr ; + bundle_t *bundle = (bundle_t *)bp->bp_longinst; + + /* save current bundle */ + *bundle = *(bundle_t *)addr ; + + /* Set the break point! */ + ((bundle_t *)addr)->lform.low8 = ( + (((bundle_t *)addr)->lform.low8 & ~INST_SLOT0_MASK) | + BREAK_INSTR); + + /* set flag */ + bp->bp_instvalid = 1 ; + + /* flush icache as it is stale now */ + ia64_flush_icache_page((unsigned long)addr) ; + +#ifdef KDB_DEBUG + kdb_printf ("[0x%016lx]: install 0x%016lx with 0x%016lx\n", + addr, bundle->lform.low8, addr[0]) ; +#endif + return 0 ; +} + +int +install_databkpt(kdb_bp_t *bp) +{ + unsigned long dbreg_addr = bp->bp_reg * 2; + unsigned long dbreg_cond = dbreg_addr + 1; + unsigned long value = 0x8fffffffffffffff; + unsigned long addr = (unsigned long)bp->bp_addr; + __asm__ ("mov dbr[%0]=%1"::"r"(dbreg_cond),"r"(value)); +// __asm__ ("movl %0,%%db0\n\t"::"r"(contents)); + __asm__ ("mov dbr[%0]=%1"::"r"(dbreg_addr),"r"(addr)); + ia64_insn_group_barrier(); + ia64_srlz_i(); + ia64_insn_group_barrier(); + +#ifdef KDB_DEBUG + kdb_printf("installed dbkpt at 0x%016lx\n", addr) ; +#endif + return 0; +} + +int +kdbinstalldbreg(kdb_bp_t *bp) +{ + if (bp->bp_mode == BKPTMODE_INST) { + return install_instbkpt(bp) ; + } else if (bp->bp_mode == BKPTMODE_DATAW) { + return install_databkpt(bp) ; + } + return 0; +} + +void +remove_instbkpt(kdb_bp_t *bp) +{ + unsigned long *addr = (unsigned long *)bp->bp_addr ; + bundle_t *bundle = (bundle_t *)bp->bp_longinst; + + if (!bp->bp_instvalid) + /* Nothing to remove. If we just alloced the bkpt + * but never resumed, the bp_inst will not be valid. */ + return ; + +#ifdef KDB_DEBUG + kdb_printf ("[0x%016lx]: remove 0x%016lx with 0x%016lx\n", + addr, addr[0], bundle->lform.low8) ; +#endif + + /* restore current bundle */ + *(bundle_t *)addr = *bundle ; + /* reset the flag */ + bp->bp_instvalid = 0 ; + ia64_flush_icache_page((unsigned long)addr) ; +} + +void +remove_databkpt(kdb_bp_t *bp) +{ + int regnum = bp->bp_reg ; + unsigned long dbreg_addr = regnum * 2; + unsigned long dbreg_cond = dbreg_addr + 1; + unsigned long value = 0x0fffffffffffffff; + __asm__ ("mov dbr[%0]=%1"::"r"(dbreg_cond),"r"(value)); +// __asm__ ("movl %0,%%db0\n\t"::"r"(contents)); + ia64_insn_group_barrier(); + ia64_srlz_i(); + ia64_insn_group_barrier(); + +#ifdef KDB_DEBUG + kdb_printf("removed dbkpt at 0x%016lx\n", bp->bp_addr) ; +#endif +} + +void +kdbremovedbreg(kdb_bp_t *bp) +{ + if (bp->bp_mode == BKPTMODE_INST) { + remove_instbkpt(bp) ; + } else if (bp->bp_mode == BKPTMODE_DATAW) { + remove_databkpt(bp) ; + } +} + +k_machreg_t +kdb_getdr6(void) +{ + return kdb_getdr(6); +} + +k_machreg_t +kdb_getdr7(void) +{ + return kdb_getdr(7); +} + +k_machreg_t +kdb_getdr(int regnum) +{ + k_machreg_t contents = 0; + unsigned long reg = (unsigned long)regnum; + + __asm__ ("mov %0=ibr[%1]"::"r"(contents),"r"(reg)); +// __asm__ ("mov ibr[%0]=%1"::"r"(dbreg_cond),"r"(value)); + + return contents; +} + + +k_machreg_t +kdb_getcr(int regnum) +{ + k_machreg_t contents = 0; + return contents; +} + +void +kdb_putdr6(k_machreg_t contents) +{ + kdb_putdr(6, contents); +} + +void +kdb_putdr7(k_machreg_t contents) +{ + kdb_putdr(7, contents); +} + +void +kdb_putdr(int regnum, k_machreg_t contents) +{ +} + +void +get_fault_regs(fault_regs_t *fr) +{ + fr->ifa = 0 ; + fr->isr = 0 ; + + __asm__ ("rsm psr.ic;;") ; + ia64_srlz_d(); + __asm__ ("mov %0=cr.ifa" : "=r"(fr->ifa)); + __asm__ ("mov %0=cr.isr" : "=r"(fr->isr)); + __asm__ ("ssm psr.ic;;") ; + ia64_srlz_d(); +} + +/* + * kdb_db_trap + * + * Perform breakpoint processing upon entry to the + * processor debugger fault. Determine and print + * the active breakpoint. + * + * Parameters: + * ef Exception frame containing machine register state + * reason Why did we enter kdb - fault or break + * Outputs: + * None. + * Returns: + * 0 Standard instruction or data breakpoint encountered + * 1 Single Step fault ('ss' command) + * 2 Single Step fault, caller should continue ('ssb' command) + * Locking: + * None. + * Remarks: + * Yup, there be goto's here. + */ + +int +kdb_db_trap(struct pt_regs *ef, int reason) +{ + int i, rv=0; + + /* Trying very hard to not change the interface to kdb. + * So, eventhough we have these values in the fault function + * it is not passed in but read again. + */ + fault_regs_t faultregs ; + + if (reason == KDB_REASON_FLTDBG) + get_fault_regs(&faultregs) ; + + /* NOTE : XXX: This has to be done only for data bkpts */ + /* Prevent it from continuously faulting */ + ef->cr_ipsr |= 0x0000002000000000; + + if (ef->cr_ipsr & 0x0000010000000000) { + /* single step */ + ef->cr_ipsr &= 0xfffffeffffffffff; + if ((kdb_state.bkpt_handling_state == BKPTSTATE_HANDLED) + && (kdb_state.cmd_given == CMDGIVEN_GO)) + ; + else + kdb_printf("SS trap at 0x%lx\n", ef->cr_iip + ia64_psr(ef)->ri); + rv = 1; + kdb_state.reason_for_entry = ENTRYREASON_SSTEP ; + goto handled; + } else + kdb_state.reason_for_entry = ENTRYREASON_GO ; + + /* + * Determine which breakpoint was encountered. + */ + for(i=0; icr_iip) || + ((faultregs.ifa) && + (breakpoints[i].bp_addr == faultregs.ifa)))) { + /* + * Hit this breakpoint. Remove it while we are + * handling hit to avoid recursion. XXX ?? + */ + if (breakpoints[i].bp_addr == faultregs.ifa) + kdb_printf("Data breakpoint #%d for 0x%lx at 0x%lx\n", + i, breakpoints[i].bp_addr, ef->cr_iip + ia64_psr(ef)->ri); + else + kdb_printf("%s breakpoint #%d at 0x%lx\n", + rwtypes[0], + i, breakpoints[i].bp_addr); + + /* + * For an instruction breakpoint, disassemble + * the current instruction. + */ +#if 0 + if (rw == 0) { + kdb_id1(ef->eip); + } +#endif + + goto handled; + } + } + +#if 0 +unknown: +#endif + kdb_printf("Unknown breakpoint. Should forward. \n"); + /* Need a flag for this. The skip should be done XXX + * when a go or single step command is done for this session. + * For now it is here. + */ + ia64_increment_ip(ef) ; + return rv ; + +handled: + + /* We are here after handling a break inst/data bkpt */ + if (kdb_state.bkpt_handling_state == BKPTSTATE_NOT_HANDLED) { + kdb_state.bkpt_handling_state = BKPTSTATE_HANDLED ; + if (kdb_state.reason_for_entry == ENTRYREASON_GO) { + kdb_setsinglestep(ef) ; + kdb_state.kdb_action = ACTION_NOBPINSTALL; + /* We dont want bp install just this once */ + kdb_state.cmd_given = CMDGIVEN_UNKNOWN ; + } + } else if (kdb_state.bkpt_handling_state == BKPTSTATE_HANDLED) { + kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ; + if (kdb_state.reason_for_entry == ENTRYREASON_SSTEP) { + if (kdb_state.cmd_given == CMDGIVEN_GO) + kdb_state.kdb_action = ACTION_NOPROMPT ; + kdb_state.cmd_given = CMDGIVEN_UNKNOWN ; + } + } else + kdb_printf("Unknown value of bkpt state\n") ; + + return rv; + +} + +void +kdb_setsinglestep(struct pt_regs *regs) +{ + regs->cr_ipsr |= 0x0000010000000000; +#if 0 + regs->eflags |= EF_TF; +#endif +} + +/* + * Symbol table functions. + */ + +/* + * kdbgetsym + * + * Return the symbol table entry for the given symbol + * + * Parameters: + * symname Character string containing symbol name + * Outputs: + * Returns: + * NULL Symbol doesn't exist + * ksp Pointer to symbol table entry + * Locking: + * None. + * Remarks: + */ + +__ksymtab_t * +kdbgetsym(const char *symname) +{ + __ksymtab_t *ksp = __kdbsymtab; + int i; + + if (symname == NULL) + return NULL; + + for (i=0; i<__kdbsymtabsize; i++, ksp++) { + if (ksp->name && (strcmp(ksp->name, symname)==0)) { + return ksp; + } + } + + return NULL; +} + +/* + * kdbgetsymval + * + * Return the address of the given symbol. + * + * Parameters: + * symname Character string containing symbol name + * Outputs: + * Returns: + * 0 Symbol name is NULL + * addr Address corresponding to symname + * Locking: + * None. + * Remarks: + */ + +unsigned long +kdbgetsymval(const char *symname) +{ + __ksymtab_t *ksp = kdbgetsym(symname); + + return (ksp?ksp->value:0); +} + +/* + * kdbaddmodsym + * + * Add a symbol to the kernel debugger symbol table. Called when + * a new module is loaded into the kernel. + * + * Parameters: + * symname Character string containing symbol name + * value Value of symbol + * Outputs: + * Returns: + * 0 Successfully added to table. + * 1 Duplicate symbol + * 2 Symbol table full + * Locking: + * None. + * Remarks: + */ + +int +kdbaddmodsym(char *symname, unsigned long value) +{ + + /* + * Check for duplicate symbols. + */ + if (kdbgetsym(symname)) { + printk("kdb: Attempt to register duplicate symbol '%s' @ 0x%lx\n", + symname, value); + return 1; + } + + if (__kdbsymtabsize < __kdbmaxsymtabsize) { + __ksymtab_t *ksp = &__kdbsymtab[__kdbsymtabsize++]; + + ksp->name = symname; + ksp->value = value; + return 0; + } + + /* + * No room left in kernel symbol table. + */ + { + static int __kdbwarn = 0; + + if (__kdbwarn == 0) { + __kdbwarn++; + printk("kdb: Exceeded symbol table size. Increase CONFIG_KDB_SYMTAB_SIZE in kernel configuration\n"); + } + } + + return 2; +} + +/* + * kdbdelmodsym + * + * Add a symbol to the kernel debugger symbol table. Called when + * a new module is loaded into the kernel. + * + * Parameters: + * symname Character string containing symbol name + * value Value of symbol + * Outputs: + * Returns: + * 0 Successfully added to table. + * 1 Symbol not found + * Locking: + * None. + * Remarks: + */ + +int +kdbdelmodsym(const char *symname) +{ + __ksymtab_t *ksp, *endksp; + + if (symname == NULL) + return 1; + + /* + * Search for the symbol. If found, move + * all successive symbols down one position + * in the symbol table to avoid leaving holes. + */ + endksp = &__kdbsymtab[__kdbsymtabsize]; + for (ksp = __kdbsymtab; ksp < endksp; ksp++) { + if (ksp->name && (strcmp(ksp->name, symname) == 0)) { + endksp--; + for ( ; ksp < endksp; ksp++) { + *ksp = *(ksp + 1); + } + __kdbsymtabsize--; + return 0; + } + } + + return 1; +} + +/* + * kdbnearsym + * + * Return the name of the symbol with the nearest address + * less than 'addr'. + * + * Parameters: + * addr Address to check for symbol near + * Outputs: + * Returns: + * NULL No symbol with address less than 'addr' + * symbol Returns the actual name of the symbol. + * Locking: + * None. + * Remarks: + */ + +char * +kdbnearsym(unsigned long addr) +{ + __ksymtab_t *ksp = __kdbsymtab; + __ksymtab_t *kpp = NULL; + int i; + + for(i=0; i<__kdbsymtabsize; i++, ksp++) { + if (!ksp->name) + continue; + + if (addr == ksp->value) { + kpp = ksp; + break; + } + if (addr > ksp->value) { + if ((kpp == NULL) + || (ksp->value > kpp->value)) { + kpp = ksp; + } + } + } + + /* + * If more than 128k away, don't bother. + */ + if ((kpp == NULL) + || ((addr - kpp->value) > 0x20000)) { + return NULL; + } + + return kpp->name; +} + +/* + * kdbgetregcontents + * + * Return the contents of the register specified by the + * input string argument. Return an error if the string + * does not match a machine register. + * + * The following pseudo register names are supported: + * ®s - Prints address of exception frame + * kesp - Prints kernel stack pointer at time of fault + * sstk - Prints switch stack for ia64 + * % - Uses the value of the registers at the + * last time the user process entered kernel + * mode, instead of the registers at the time + * kdb was entered. + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * Outputs: + * *contents Pointer to unsigned long to recieve register contents + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + * + * Note that this function is really machine independent. The kdb + * register list is not, however. + */ + +static struct kdbregs { + char *reg_name; + size_t reg_offset; +} kdbreglist[] = { + { " psr", offsetof(struct pt_regs, cr_ipsr) }, + { " ifs", offsetof(struct pt_regs, cr_ifs) }, + { " ip", offsetof(struct pt_regs, cr_iip) }, + + { "unat", offsetof(struct pt_regs, ar_unat) }, + { " pfs", offsetof(struct pt_regs, ar_pfs) }, + { " rsc", offsetof(struct pt_regs, ar_rsc) }, + + { "rnat", offsetof(struct pt_regs, ar_rnat) }, + { "bsps", offsetof(struct pt_regs, ar_bspstore) }, + { " pr", offsetof(struct pt_regs, pr) }, + + { "ldrs", offsetof(struct pt_regs, loadrs) }, + { " ccv", offsetof(struct pt_regs, ar_ccv) }, + { "fpsr", offsetof(struct pt_regs, ar_fpsr) }, + + { " b0", offsetof(struct pt_regs, b0) }, + { " b6", offsetof(struct pt_regs, b6) }, + { " b7", offsetof(struct pt_regs, b7) }, + + { " r1",offsetof(struct pt_regs, r1) }, + { " r2",offsetof(struct pt_regs, r2) }, + { " r3",offsetof(struct pt_regs, r3) }, + + { " r8",offsetof(struct pt_regs, r8) }, + { " r9",offsetof(struct pt_regs, r9) }, + { " r10",offsetof(struct pt_regs, r10) }, + + { " r11",offsetof(struct pt_regs, r11) }, + { " r12",offsetof(struct pt_regs, r12) }, + { " r13",offsetof(struct pt_regs, r13) }, + + { " r14",offsetof(struct pt_regs, r14) }, + { " r15",offsetof(struct pt_regs, r15) }, + { " r16",offsetof(struct pt_regs, r16) }, + + { " r17",offsetof(struct pt_regs, r17) }, + { " r18",offsetof(struct pt_regs, r18) }, + { " r19",offsetof(struct pt_regs, r19) }, + + { " r20",offsetof(struct pt_regs, r20) }, + { " r21",offsetof(struct pt_regs, r21) }, + { " r22",offsetof(struct pt_regs, r22) }, + + { " r23",offsetof(struct pt_regs, r23) }, + { " r24",offsetof(struct pt_regs, r24) }, + { " r25",offsetof(struct pt_regs, r25) }, + + { " r26",offsetof(struct pt_regs, r26) }, + { " r27",offsetof(struct pt_regs, r27) }, + { " r28",offsetof(struct pt_regs, r28) }, + + { " r29",offsetof(struct pt_regs, r29) }, + { " r30",offsetof(struct pt_regs, r30) }, + { " r31",offsetof(struct pt_regs, r31) }, + +}; + +static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); + +int +kdbgetregcontents(const char *regname, + struct pt_regs *regs, + unsigned long *contents) +{ + int i; + + if (strcmp(regname, "®s") == 0) { + *contents = (unsigned long)regs; + return 0; + } + + if (strcmp(regname, "sstk") == 0) { + *contents = (unsigned long)getprsregs(regs) ; + return 0; + } + + if (strcmp(regname, "isr") == 0) { + fault_regs_t fr ; + get_fault_regs(&fr) ; + *contents = fr.isr ; + return 0 ; + } + +#if 0 + /* XXX need to verify this */ + if (strcmp(regname, "kesp") == 0) { + *contents = (unsigned long)regs + sizeof(struct pt_regs); + return 0; + } + + if (regname[0] == '%') { + /* User registers: %%e[a-c]x, etc */ + regname++; + regs = (struct pt_regs *) + (current->thread.ksp - sizeof(struct pt_regs)); + } +#endif + + for (i=0; i + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * contents Unsigned long containing new register contents + * Outputs: + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + */ + +int +kdbsetregcontents(const char *regname, + struct pt_regs *regs, + unsigned long contents) +{ + int i; + + if (regname[0] == '%') { + regname++; + regs = (struct pt_regs *) + (current->thread.ksp - sizeof(struct pt_regs)); + } + + for (i=0; ithread.ksp - sizeof(struct pt_regs)); + } + + if (type == NULL) { + for (i=0; icr_iip + ia64_psr(regs)->ri; +} + +int +kdb_setpc(struct pt_regs *regs, k_machreg_t newpc) +{ + regs->cr_iip = newpc & ~0xf; + ia64_psr(regs)->ri = newpc & 0x3; + return 0; +} + +void +kdb_disableint(kdbintstate_t *state) +{ + int *fp = (int *)state; + int flags; + + __save_flags(flags); + __cli(); + + *fp = flags; +} + +void +kdb_restoreint(kdbintstate_t *state) +{ + int flags = *(int *)state; + __restore_flags(flags); +} + +int +kdb_putword(unsigned long addr, unsigned long contents) +{ + *(unsigned long *)addr = contents; + return 0; +} + +int +kdb_getcurrentframe(struct pt_regs *regs) +{ +#if 0 + regs->xcs = 0; +#if defined(CONFIG_KDB_FRAMEPTR) + asm volatile("movl %%ebp,%0":"=m" (*(int *)®s->ebp)); +#endif + asm volatile("movl %%esp,%0":"=m" (*(int *)®s->esp)); +#endif + return 0; +} + +unsigned long +show_cur_stack_frame(struct pt_regs *regs, int regno, unsigned long *contents) +{ + long sof = regs->cr_ifs & ((1<<7)-1) ; /* size of frame */ + unsigned long i ; + int j; + struct switch_stack *prs_regs = getprsregs(regs) ; + unsigned long *sofptr = (prs_regs? ia64_rse_skip_regs( + (unsigned long *)prs_regs->ar_bspstore, -sof) : NULL) ; + + if (!sofptr) { + printk("Unable to display Current Stack Frame\n") ; + return 0 ; + } + + if (regno < 0) + return 0 ; + + for (i=sof, j=0;i;i--,j++) { + /* remember to skip the nat collection dword */ + if ((((unsigned long)sofptr>>3) & (((1<<6)-1))) + == ((1<<6)-1)) + sofptr++ ; + + /* return the value in the reg if regno is non zero */ + + if (regno) { + if ((j+1) == regno) { + if (contents) + *contents = *sofptr ; + return -1; + } + sofptr++ ; + } else { + printk(" r%d: %016lx ", 32+j, *sofptr++) ; + if (!((j+1)%3)) printk("\n") ; + } + } + + if (regno) { + if (!i) /* bogus rse number */ + return 0 ; + } else + printk("\n") ; + + return 0 ; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kdb/pc_keyb.h linux/arch/ia64/kdb/pc_keyb.h --- v2.3.42/linux/arch/ia64/kdb/pc_keyb.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kdb/pc_keyb.h Sun Feb 6 18:42:40 2000 @@ -0,0 +1,127 @@ +/* + * linux/drivers/char/pc_keyb.h + * + * PC Keyboard And Keyboard Controller + * + * (c) 1997 Martin Mares + */ + +/* + * Configuration Switches + */ + +#undef KBD_REPORT_ERR /* Report keyboard errors */ +#define KBD_REPORT_UNKN /* Report unknown scan codes */ +#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ +#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ +#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ + + + +#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ +#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ +#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ + +/* + * Internal variables of the driver + */ + +extern unsigned char pckbd_read_mask; +extern unsigned char aux_device_present; + +/* + * Keyboard Controller Registers + */ + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* + * Mouse Commands + */ + +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ + +#define AUX_BUF_SIZE 2048 + +struct aux_queue { + unsigned long head; + unsigned long tail; + struct wait_queue *proc_list; + struct fasync_struct *fasync; + unsigned char buf[AUX_BUF_SIZE]; +}; + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile --- v2.3.42/linux/arch/ia64/kernel/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/Makefile Wed Feb 9 19:45:43 2000 @@ -0,0 +1,42 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + +all: kernel.o head.o init_task.o + +O_TARGET := kernel.o +O_OBJS := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_default.o irq_internal.o ivt.o \ + pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o sal_stub.o semaphore.o setup.o signal.o \ + sys_ia64.o traps.o time.o unaligned.o unwind.o +#O_OBJS := fpreg.o +#OX_OBJS := ia64_ksyms.o + +ifeq ($(CONFIG_IA64_GENERIC),y) +O_OBJS += machvec.o +endif + +ifdef CONFIG_PCI +O_OBJS += pci.o +endif + +ifdef CONFIG_SMP +O_OBJS += smp.o irq_lock.o +endif + +ifeq ($(CONFIG_MCA),y) +O_OBJS += mca.o mca_asm.o +endif + +clean:: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c --- v2.3.42/linux/arch/ia64/kernel/acpi.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/acpi.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,308 @@ +/* + * Advanced Configuration and Power Interface + * + * Based on 'ACPI Specification 1.0b' February 2, 1999 and + * 'IA-64 Extensions to ACPI Specification' Revision 0.6 + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999,2000 Walt Drummond + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#undef ACPI_DEBUG /* Guess what this does? */ + +#ifdef CONFIG_SMP +extern unsigned long ipi_base_addr; +#endif + +/* These are ugly but will be reclaimed by the kernel */ +int __initdata acpi_cpus = 0; +int __initdata acpi_apic_map[32]; +int __initdata cpu_cnt = 0; + +void (*pm_idle) (void); + +/* + * Identify usable CPU's and remember them for SMP bringup later. + */ +static void __init +acpi_lsapic(char *p) +{ + int add = 1; + + acpi_entry_lsapic_t *lsapic = (acpi_entry_lsapic_t *) p; + + if ((lsapic->flags & LSAPIC_PRESENT) == 0) + return; + + printk(" CPU %d (%.04x:%.04x): ", cpu_cnt, lsapic->eid, lsapic->id); + + if ((lsapic->flags & LSAPIC_ENABLED) == 0) { + printk("Disabled.\n"); + add = 0; + } else if (lsapic->flags & LSAPIC_PERFORMANCE_RESTRICTED) { + printk("Performance Restricted; ignoring.\n"); + add = 0; + } + + if (add) { + printk("Available.\n"); + acpi_cpus++; + acpi_apic_map[cpu_cnt] = (lsapic->id << 8) | lsapic->eid; + } + + cpu_cnt++; +} + +/* + * Find all IOSAPICs and tag the iosapic_vector structure with the appropriate + * base addresses. + */ +static void __init +acpi_iosapic(char *p) +{ + /* + * This is not good. ACPI is not necessarily limited to CONFIG_IA64_SV, yet + * ACPI does not necessarily imply IOSAPIC either. Perhaps there should be + * a means for platform_setup() to register ACPI handlers? + */ +#ifdef CONFIG_IA64_DIG + acpi_entry_iosapic_t *iosapic = (acpi_entry_iosapic_t *) p; + unsigned int ver; + int l, v, pins; + + ver = iosapic_version(iosapic->address); + pins = (ver >> 16) & 0xff; + + printk("IOSAPIC Version %x.%x: address 0x%lx IRQs 0x%x - 0x%x\n", + (ver & 0xf0) >> 4, (ver & 0x0f), iosapic->address, + iosapic->irq_base, iosapic->irq_base + pins); + + for (l = 0; l < pins; l++) { + v = map_legacy_irq(iosapic->irq_base + l); + if (v > IA64_MAX_VECTORED_IRQ) { + printk(" !!! IRQ %d > 255\n", v); + continue; + } + /* XXX Check for IOSAPIC collisions */ + iosapic_addr(v) = (unsigned long) ioremap(iosapic->address, 0); + iosapic_baseirq(v) = iosapic->irq_base; + } + iosapic_init(iosapic->address); +#endif +} + + +/* + * Configure legacy IRQ information in iosapic_vector + */ +static void __init +acpi_legacy_irq(char *p) +{ + /* + * This is not good. ACPI is not necessarily limited to CONFIG_IA64_SV, yet + * ACPI does not necessarily imply IOSAPIC either. Perhaps there should be + * a means for platform_setup() to register ACPI handlers? + */ +#ifdef CONFIG_IA64_IRQ_ACPI + acpi_entry_int_override_t *legacy = (acpi_entry_int_override_t *) p; + unsigned char vector; + int i; + + vector = map_legacy_irq(legacy->isa_irq); + + /* + * Clobber any old pin mapping. It may be that it gets replaced later on + */ + for (i = 0; i < IA64_MAX_VECTORED_IRQ; i++) { + if (i == vector) + continue; + if (iosapic_pin(i) == iosapic_pin(vector)) + iosapic_pin(i) = 0xff; + } + + iosapic_pin(vector) = legacy->pin; + iosapic_bus(vector) = BUS_ISA; /* This table only overrides the ISA devices */ + iosapic_busdata(vector) = 0; + + /* + * External timer tick is special... + */ + if (vector != TIMER_IRQ) + iosapic_dmode(vector) = IO_SAPIC_LOWEST_PRIORITY; + else + iosapic_dmode(vector) = IO_SAPIC_FIXED; + + /* See MPS 1.4 section 4.3.4 */ + switch (legacy->flags) { + case 0x5: + iosapic_polarity(vector) = IO_SAPIC_POL_HIGH; + iosapic_trigger(vector) = IO_SAPIC_EDGE; + break; + case 0x8: + iosapic_polarity(vector) = IO_SAPIC_POL_LOW; + iosapic_trigger(vector) = IO_SAPIC_EDGE; + break; + case 0xd: + iosapic_polarity(vector) = IO_SAPIC_POL_HIGH; + iosapic_trigger(vector) = IO_SAPIC_LEVEL; + break; + case 0xf: + iosapic_polarity(vector) = IO_SAPIC_POL_LOW; + iosapic_trigger(vector) = IO_SAPIC_LEVEL; + break; + default: + printk(" ACPI Legacy IRQ 0x%02x: Unknown flags 0x%x\n", legacy->isa_irq, + legacy->flags); + break; + } + +#ifdef ACPI_DEBUG + printk("Legacy ISA IRQ %x -> IA64 Vector %x IOSAPIC Pin %x Active %s %s Trigger\n", + legacy->isa_irq, vector, iosapic_pin(vector), + ((iosapic_polarity(vector) == IO_SAPIC_POL_LOW) ? "Low" : "High"), + ((iosapic_trigger(vector) == IO_SAPIC_LEVEL) ? "Level" : "Edge")); +#endif /* ACPI_DEBUG */ + +#endif /* CONFIG_IA64_IRQ_ACPI */ +} + +/* + * Info on platform interrupt sources: NMI. PMI, INIT, etc. + */ +static void __init +acpi_platform(char *p) +{ + acpi_entry_platform_src_t *plat = (acpi_entry_platform_src_t *) p; + + printk("PLATFORM: IOSAPIC %x -> Vector %lx on CPU %.04u:%.04u\n", + plat->iosapic_vector, plat->global_vector, plat->eid, plat->id); +} + +/* + * Parse the ACPI Multiple SAPIC Table + */ +static void __init +acpi_parse_msapic(acpi_sapic_t *msapic) +{ + char *p, *end; + + memset(&acpi_apic_map, -1, sizeof(acpi_apic_map)); + +#ifdef CONFIG_SMP + /* Base address of IPI Message Block */ + ipi_base_addr = ioremap(msapic->interrupt_block, 0); +#endif + + p = (char *) (msapic + 1); + end = p + (msapic->header.length - sizeof(acpi_sapic_t)); + + while (p < end) { + + switch (*p) { + case ACPI_ENTRY_LOCAL_SAPIC: + acpi_lsapic(p); + break; + + case ACPI_ENTRY_IO_SAPIC: + acpi_iosapic(p); + break; + + case ACPI_ENTRY_INT_SRC_OVERRIDE: + acpi_legacy_irq(p); + break; + + case ACPI_ENTRY_PLATFORM_INT_SOURCE: + acpi_platform(p); + break; + + default: + break; + } + + /* Move to next table entry. */ + p += *(p + 1); + } + + /* Make bootup pretty */ + printk(" %d CPUs available, %d CPUs total\n", acpi_cpus, cpu_cnt); +} + +int __init +acpi_parse(acpi_rsdp_t *rsdp) +{ + acpi_rsdt_t *rsdt; + acpi_desc_table_hdr_t *hdrp; + long tables, i; + + if (!rsdp) { + printk("Uh-oh, no ACPI Root System Description Pointer table!\n"); + return 0; + } + + if (strncmp(rsdp->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) { + printk("Uh-oh, ACPI RSDP signature incorrect!\n"); + return 0; + } + + rsdp->rsdt = __va(rsdp->rsdt); + rsdt = rsdp->rsdt; + if (strncmp(rsdt->header.signature, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN)) { + printk("Uh-oh, ACPI RDST signature incorrect!\n"); + return 0; + } + + printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, + rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff); + + tables = (rsdt->header.length - sizeof(acpi_desc_table_hdr_t)) / 8; + for (i = 0; i < tables; i++) { + hdrp = (acpi_desc_table_hdr_t *) __va(rsdt->entry_ptrs[i]); + + /* Only interested int the MSAPIC table for now ... */ + if (strncmp(hdrp->signature, ACPI_SAPIC_SIG, ACPI_SAPIC_SIG_LEN) != 0) + continue; + + acpi_parse_msapic((acpi_sapic_t *) hdrp); + } /* while() */ + + if (acpi_cpus == 0) { + printk("ACPI: Found 0 CPUS; assuming 1\n"); + acpi_cpus = 1; /* We've got at least one of these, no? */ + } + return 1; +} + +const char * +acpi_get_sysname (void) +{ + /* the following should go away once we have an ACPI parser: */ +#ifdef CONFIG_IA64_GENERIC + return "hpsim"; +#else +# if defined (CONFIG_IA64_HP_SIM) + return "hpsim"; +# elif defined (CONFIG_IA64_SGI_SN1_SIM) + return "sn1"; +# elif defined (CONFIG_IA64_DIG) + return "dig"; +# else +# error Unknown platform. Fix acpi.c. +# endif +#endif +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.3.42/linux/arch/ia64/kernel/efi.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/efi.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,365 @@ +/* + * Extensible Firmware Interface + * + * Based on Extensible Firmware Interface Specification version 0.9 April 30, 1999 + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999 Hewlett-Packard Co. + * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999 Stephane Eranian + * + * All EFI Runtime Services are not implemented yet as EFI only + * supports physical mode addressing on SoftSDV. This is to be fixed + * in a future version. --drummond 1999-07-20 + * + * Implemented EFI runtime services and virtual mode calls. --davidm + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#define EFI_DEBUG + +extern efi_status_t efi_call_phys (void *, ...); + +struct efi efi; + +static efi_runtime_services_t *runtime; + +static efi_status_t +phys_get_time (efi_time_t *tm, efi_time_cap_t *tc) +{ + return efi_call_phys(__va(runtime->get_time), __pa(tm), __pa(tc)); +} + +static efi_status_t +phys_set_time (efi_time_t *tm) +{ + return efi_call_phys(__va(runtime->set_time), __pa(tm)); +} + +static efi_status_t +phys_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) +{ + return efi_call_phys(__va(runtime->get_wakeup_time), __pa(enabled), __pa(pending), + __pa(tm)); +} + +static efi_status_t +phys_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) +{ + return efi_call_phys(__va(runtime->set_wakeup_time), enabled, __pa(tm)); +} + +static efi_status_t +phys_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, + unsigned long *data_size, void *data) +{ + return efi_call_phys(__va(runtime->get_variable), __pa(name), __pa(vendor), __pa(attr), + __pa(data_size), __pa(data)); +} + +static efi_status_t +phys_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor) +{ + return efi_call_phys(__va(runtime->get_next_variable), __pa(name_size), __pa(name), + __pa(vendor)); +} + +static efi_status_t +phys_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr, + unsigned long data_size, void *data) +{ + return efi_call_phys(__va(runtime->set_variable), __pa(name), __pa(vendor), attr, + data_size, __pa(data)); +} + +static efi_status_t +phys_get_next_high_mono_count (u64 *count) +{ + return efi_call_phys(__va(runtime->get_next_high_mono_count), __pa(count)); +} + +static void +phys_reset_system (int reset_type, efi_status_t status, + unsigned long data_size, efi_char16_t *data) +{ + efi_call_phys(__va(runtime->reset_system), status, data_size, __pa(data)); +} + +/* + * Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long +mktime (unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((((unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +void +efi_gettimeofday (struct timeval *tv) +{ + efi_time_t tm; + + memset(tv, 0, sizeof(tv)); + if ((*efi.get_time)(&tm, 0) != EFI_SUCCESS) + return; + + tv->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second); + tv->tv_usec = tm.nanosecond / 1000; +} + +/* + * Walks the EFI memory map and calls CALLBACK once for each EFI + * memory descriptor that has memory that is available for OS use. + */ +void +efi_memmap_walk (efi_freemem_callback_t callback, void *arg) +{ + int prev_valid = 0; + struct range { + u64 start; + u64 end; + } prev, curr; + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size, start, end; + + efi_map_start = __va(ia64_boot_param.efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; + efi_desc_size = ia64_boot_param.efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + switch (md->type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: +#ifndef CONFIG_IA64_VIRTUAL_MEM_MAP + if (md->phys_addr > 1024*1024*1024UL) { + printk("Warning: ignoring %luMB of memory above 1GB!\n", + md->num_pages >> 8); + md->type = EFI_UNUSABLE_MEMORY; + continue; + } +#endif + + curr.start = PAGE_OFFSET + md->phys_addr; + curr.end = curr.start + (md->num_pages << 12); + + if (!prev_valid) { + prev = curr; + prev_valid = 1; + } else { + if (curr.start < prev.start) + printk("Oops: EFI memory table not ordered!\n"); + + if (prev.end == curr.start) { + /* merge two consecutive memory ranges */ + prev.end = curr.end; + } else { + start = PAGE_ALIGN(prev.start); + end = prev.end & PAGE_MASK; + if ((end > start) && (*callback)(start, end, arg) < 0) + return; + prev = curr; + } + } + break; + + default: + continue; + } + } + if (prev_valid) { + start = PAGE_ALIGN(prev.start); + end = prev.end & PAGE_MASK; + if (end > start) + (*callback)(start, end, arg); + } +} + +void __init +efi_init (void) +{ + void *efi_map_start, *efi_map_end, *p; + efi_config_table_t *config_tables; + efi_memory_desc_t *md; + efi_char16_t *c16; + u64 efi_desc_size; + char vendor[100] = "unknown"; + int i; + + efi.systab = __va(ia64_boot_param.efi_systab); + + /* + * Verify the EFI Table + */ + if (efi.systab == NULL) + panic("Woah! Can't find EFI system table.\n"); + if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) + panic("Woah! EFI system table signature incorrect\n"); + if (efi.systab->hdr.revision != EFI_SYSTEM_TABLE_REVISION) + printk("Warning: EFI system table version mismatch: " + "got %d.%02d, expected %d.%02d\n", + efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, + EFI_SYSTEM_TABLE_REVISION >> 16, EFI_SYSTEM_TABLE_REVISION & 0xffff); + + config_tables = __va(efi.systab->tables); + + /* Show what we know for posterity */ + c16 = __va(efi.systab->fw_vendor); + if (c16) { + for (i = 0;i < sizeof(vendor) && *c16; ++i) + vendor[i] = *c16++; + vendor[i] = '\0'; + } + + printk("EFI v%u.%.02u by %s:", + efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor); + + for (i = 0; i < efi.systab->nr_tables; i++) { + if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) { + efi.mps = __va(config_tables[i].table); + printk(" MPS=0x%lx", config_tables[i].table); + } else if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) { + efi.acpi = __va(config_tables[i].table); + printk(" ACPI=0x%lx", config_tables[i].table); + } else if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) { + efi.smbios = __va(config_tables[i].table); + printk(" SMBIOS=0x%lx", config_tables[i].table); + } else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) { + efi.sal_systab = __va(config_tables[i].table); + printk(" SALsystab=0x%lx", config_tables[i].table); + } + } + printk("\n"); + + runtime = __va(efi.systab->runtime); + efi.get_time = phys_get_time; + efi.set_time = phys_set_time; + efi.get_wakeup_time = phys_get_wakeup_time; + efi.set_wakeup_time = phys_set_wakeup_time; + efi.get_variable = phys_get_variable; + efi.get_next_variable = phys_get_next_variable; + efi.set_variable = phys_set_variable; + efi.get_next_high_mono_count = phys_get_next_high_mono_count; + efi.reset_system = phys_reset_system; + + efi_map_start = __va(ia64_boot_param.efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; + efi_desc_size = ia64_boot_param.efi_memdesc_size; + +#ifdef EFI_DEBUG + /* print EFI memory map: */ + for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) { + md = p; + printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n", + i, md->type, md->attribute, + md->phys_addr, md->phys_addr + (md->num_pages<<12) - 1, md->num_pages >> 8); + } +#endif +} + +void +efi_enter_virtual_mode (void) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + efi_status_t status; + u64 efi_desc_size; + + efi_map_start = __va(ia64_boot_param.efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param.efi_memmap_size; + efi_desc_size = ia64_boot_param.efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + if (md->attribute & EFI_MEMORY_RUNTIME) { + /* + * Some descriptors have multiple bits set, so the order of + * the tests is relevant. + */ + if (md->attribute & EFI_MEMORY_WB) { + md->virt_addr = (u64) __va(md->phys_addr); + } else if (md->attribute & EFI_MEMORY_UC) { + md->virt_addr = (u64) ioremap(md->phys_addr, 0); + } else if (md->attribute & EFI_MEMORY_WC) { +#if 0 + md->virt_addr = ia64_remap(md->phys_addr, (_PAGE_A | _PAGE_P + | _PAGE_D + | _PAGE_MA_WC + | _PAGE_PL_0 + | _PAGE_AR_RW)); +#else + printk("EFI_MEMORY_WC mapping\n"); + md->virt_addr = (u64) ioremap(md->phys_addr, 0); +#endif + } else if (md->attribute & EFI_MEMORY_WT) { +#if 0 + md->virt_addr = ia64_remap(md->phys_addr, (_PAGE_A | _PAGE_P + | _PAGE_D | _PAGE_MA_WT + | _PAGE_PL_0 + | _PAGE_AR_RW)); +#else + printk("EFI_MEMORY_WT mapping\n"); + md->virt_addr = (u64) ioremap(md->phys_addr, 0); +#endif + } + } + } + + status = efi_call_phys(__va(runtime->set_virtual_address_map), + ia64_boot_param.efi_memmap_size, + efi_desc_size, ia64_boot_param.efi_memdesc_version, + ia64_boot_param.efi_memmap); + if (status != EFI_SUCCESS) { + printk("Warning: unable to switch EFI into virtual mode (status=%lu)\n", status); + return; + } + + /* + * Now that EFI is in virtual mode, we arrange for EFI functions to be + * called directly: + */ + efi.get_time = __va(runtime->get_time); + efi.set_time = __va(runtime->set_time); + efi.get_wakeup_time = __va(runtime->get_wakeup_time); + efi.set_wakeup_time = __va(runtime->set_wakeup_time); + efi.get_variable = __va(runtime->get_variable); + efi.get_next_variable = __va(runtime->get_next_variable); + efi.set_variable = __va(runtime->set_variable); + efi.get_next_high_mono_count = __va(runtime->get_next_high_mono_count); + efi.reset_system = __va(runtime->reset_system); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/efi_stub.S linux/arch/ia64/kernel/efi_stub.S --- v2.3.42/linux/arch/ia64/kernel/efi_stub.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/efi_stub.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,141 @@ +/* + * EFI call stub. + * + * Copyright (C) 1999 David Mosberger + * + * This stub allows us to make EFI calls in physical mode with interrupts + * turned off. We need this because we can't call SetVirtualMap() until + * the kernel has booted far enough to allow allocation of struct vma_struct + * entries (which we would need to map stuff with memory attributes other + * than uncached or writeback...). Since the GetTime() service gets called + * earlier than that, we need to be able to make physical mode EFI calls from + * the kernel. + */ + +/* + * PSR settings as per SAL spec (Chapter 8 in the "IA-64 System + * Abstraction Layer Specification", revision 2.6e). Note that + * psr.dfl and psr.dfh MUST be cleared, despite what this manual says. + * Otherwise, SAL dies whenever it's trying to do an IA-32 BIOS call + * (the br.ia instruction fails unless psr.dfl and psr.dfh are + * cleared). Fortunately, SAL promises not to touch the floating + * point regs, so at least we don't have to save f2-f127. + */ +#define PSR_BITS_TO_CLEAR \ + (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \ + IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \ + IA64_PSR_DFL | IA64_PSR_DFH) + +#define PSR_BITS_TO_SET \ + (IA64_PSR_BN) + +#include + + .text + .psr abi64 + .psr lsb + .lsb + + .text + +/* + * Switch execution mode from virtual to physical or vice versa. + * + * Inputs: + * r16 = new psr to establish + */ + .proc switch_mode +switch_mode: + { + alloc r2=ar.pfs,0,0,0,0 + rsm psr.i | psr.ic // disable interrupts and interrupt collection + mov r15=ip + } + ;; + { + flushrs // must be first insn in group + srlz.i + shr.u r19=r15,61 // r19 <- top 3 bits of current IP + } + ;; + mov cr.ipsr=r16 // set new PSR + add r3=1f-switch_mode,r15 + xor r15=0x7,r19 // flip the region bits + + mov r17=ar.bsp + mov r14=rp // get return address into a general register + + // switch RSE backing store: + ;; + dep r17=r15,r17,61,3 // make ar.bsp physical or virtual + mov r18=ar.rnat // save ar.rnat + ;; + mov ar.bspstore=r17 // this steps on ar.rnat + dep r3=r15,r3,61,3 // make rfi return address physical or virtual + ;; + mov cr.iip=r3 + mov cr.ifs=r0 + dep sp=r15,sp,61,3 // make stack pointer physical or virtual + ;; + mov ar.rnat=r18 // restore ar.rnat + dep r14=r15,r14,61,3 // make function return address physical or virtual + rfi // must be last insn in group + ;; +1: mov rp=r14 + br.ret.sptk.few rp + .endp switch_mode + +/* + * Inputs: + * in0 = address of function descriptor of EFI routine to call + * in1..in7 = arguments to routine + * + * Outputs: + * r8 = EFI_STATUS returned by called function + */ + + .global efi_call_phys + .proc efi_call_phys +efi_call_phys: + + alloc loc0=ar.pfs,8,5,7,0 + ld8 r2=[in0],8 // load EFI function's entry point + mov loc1=rp + ;; + mov loc2=gp // save global pointer + mov loc4=ar.rsc // save RSE configuration + mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + ;; + + ld8 gp=[in0] // load EFI function's global pointer + mov out0=in1 + mov out1=in2 + movl r16=PSR_BITS_TO_CLEAR + + mov loc3=psr // save processor status word + movl r17=PSR_BITS_TO_SET + ;; + mov out2=in3 + or loc3=loc3,r17 + mov b6=r2 + ;; + andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared + mov out3=in4 + br.call.sptk.few rp=switch_mode +.ret0: + mov out4=in5 + mov out5=in6 + mov out6=in7 + br.call.sptk.few rp=b6 // call the EFI function +.ret1: + mov ar.rsc=r0 // put RSE in enforced lazy, LE mode + mov r16=loc3 + br.call.sptk.few rp=switch_mode // return to virtual mode +.ret2: + mov ar.rsc=loc4 // restore RSE configuration + mov ar.pfs=loc0 + mov rp=loc1 + mov gp=loc2 + br.ret.sptk.few rp + + .endp efi_call_phys diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.3.42/linux/arch/ia64/kernel/entry.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/entry.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,1261 @@ +/* + * ia64/kernel/entry.S + * + * Kernel entry points. + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999 Asit Mallick + * Copyright (C) 1999 Don Dugger + */ +/* + * Global (preserved) predicate usage on syscall entry/exit path: + * + * + * pEOI: See entry.h. + * pKern: See entry.h. + * pSys: See entry.h. + * pNonSys: !pSys + * p2: (Alias of pKern!) True if any signals are pending. + * p16/p17: Used by stubs calling ia64_do_signal to indicate if current task + * has PF_PTRACED flag bit set. p16 is true if so, p17 is the complement. + */ + +#include + +#include +#include +#include +#include + +#include "entry.h" + + .text + .psr abi64 + .psr lsb + .lsb + + /* + * execve() is special because in case of success, we need to + * setup a null register window frame. + */ + .align 16 + .proc ia64_execve +ia64_execve: + alloc loc0=ar.pfs,3,2,4,0 + mov loc1=rp + mov out0=in0 // filename + ;; // stop bit between alloc and call + mov out1=in1 // argv + mov out2=in2 // envp + add out3=16,sp // regs + br.call.sptk.few rp=sys_execve +.ret0: cmp4.ge p6,p0=r8,r0 + mov ar.pfs=loc0 // restore ar.pfs + ;; +(p6) mov ar.pfs=r0 // clear ar.pfs in case of success + sxt4 r8=r8 // return 64-bit result + mov rp=loc1 + + br.ret.sptk.few rp + .endp ia64_execve + + .align 16 + .global sys_clone + .proc sys_clone +sys_clone: + alloc r16=ar.pfs,2,2,3,0;; + movl r28=1f + mov loc1=rp + br.cond.sptk.many save_switch_stack +1: + mov loc0=r16 // save ar.pfs across do_fork + adds out2=IA64_SWITCH_STACK_SIZE+16,sp + adds r2=IA64_SWITCH_STACK_SIZE+IA64_PT_REGS_R12_OFFSET+16,sp + cmp.eq p8,p9=in1,r0 // usp == 0? + mov out0=in0 // out0 = clone_flags + ;; +(p8) ld8 out1=[r2] // fetch usp from pt_regs.r12 +(p9) mov out1=in1 + br.call.sptk.few rp=do_fork +.ret1: + mov ar.pfs=loc0 + adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack + mov rp=loc1 + ;; + br.ret.sptk.many rp + .endp sys_clone + +/* + * prev_task <- switch_to(struct task_struct *next) + */ + .align 16 + .global ia64_switch_to + .proc ia64_switch_to +ia64_switch_to: + alloc r16=ar.pfs,1,0,0,0 + movl r28=1f + br.cond.sptk.many save_switch_stack +1: + // disable interrupts to ensure atomicity for next few instructions: + mov r17=psr // M-unit + ;; + rsm psr.i // M-unit + dep r18=-1,r0,0,61 // build mask 0x1fffffffffffffff + ;; + srlz.d + ;; + adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 + adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 + ;; + st8 [r22]=sp // save kernel stack pointer of old task + ld8 sp=[r21] // load kernel stack pointer of new task + and r20=in0,r18 // physical address of "current" + ;; + mov r8=r13 // return pointer to previously running task + mov r13=in0 // set "current" pointer + mov ar.k6=r20 // copy "current" into ar.k6 + ;; + // restore interrupts + mov psr.l=r17 + ;; + srlz.d + + movl r28=1f + br.cond.sptk.many load_switch_stack +1: + br.ret.sptk.few rp + .endp ia64_switch_to + + /* + * Like save_switch_stack, but also save the stack frame that is active + * at the time this function is called. + */ + .align 16 + .proc save_switch_stack_with_current_frame +save_switch_stack_with_current_frame: +1: { + alloc r16=ar.pfs,0,0,0,0 // pass ar.pfs to save_switch_stack + mov r28=ip + } + ;; + adds r28=1f-1b,r28 + br.cond.sptk.many save_switch_stack +1: br.ret.sptk.few rp + .endp save_switch_stack_with_current_frame +/* + * Note that interrupts are enabled during save_switch_stack and + * load_switch_stack. This means that we may get an interrupt with + * "sp" pointing to the new kernel stack while ar.bspstore is still + * pointing to the old kernel backing store area. Since ar.rsc, + * ar.rnat, ar.bsp, and ar.bspstore are all preserved by interrupts, + * this is not a problem. + */ + +/* + * save_switch_stack: + * - r16 holds ar.pfs + * - r28 holds address to return to + * - rp (b0) holds return address to save + */ + .align 16 + .global save_switch_stack + .proc save_switch_stack +save_switch_stack: + flushrs // flush dirty regs to backing store (must be first in insn group) + mov r17=ar.unat // preserve caller's + adds r2=-IA64_SWITCH_STACK_SIZE+16,sp // r2 = &sw->caller_unat + ;; + mov r18=ar.fpsr // preserve fpsr + mov ar.rsc=r0 // put RSE in mode: enforced lazy, little endian, pl 0 + ;; + mov r19=ar.rnat + adds r3=-IA64_SWITCH_STACK_SIZE+24,sp // r3 = &sw->ar_fpsr + + // Note: the instruction ordering is important here: we can't + // store anything to the switch stack before sp is updated + // as otherwise an interrupt might overwrite the memory! + adds sp=-IA64_SWITCH_STACK_SIZE,sp + ;; + st8 [r2]=r17,16 + st8 [r3]=r18,24 + ;; + stf.spill [r2]=f2,32 + stf.spill [r3]=f3,32 + mov r21=b0 + ;; + stf.spill [r2]=f4,32 + stf.spill [r3]=f5,32 + ;; + stf.spill [r2]=f10,32 + stf.spill [r3]=f11,32 + mov r22=b1 + ;; + stf.spill [r2]=f12,32 + stf.spill [r3]=f13,32 + mov r23=b2 + ;; + stf.spill [r2]=f14,32 + stf.spill [r3]=f15,32 + mov r24=b3 + ;; + stf.spill [r2]=f16,32 + stf.spill [r3]=f17,32 + mov r25=b4 + ;; + stf.spill [r2]=f18,32 + stf.spill [r3]=f19,32 + mov r26=b5 + ;; + stf.spill [r2]=f20,32 + stf.spill [r3]=f21,32 + mov r17=ar.lc // I-unit + ;; + stf.spill [r2]=f22,32 + stf.spill [r3]=f23,32 + ;; + stf.spill [r2]=f24,32 + stf.spill [r3]=f25,32 + ;; + stf.spill [r2]=f26,32 + stf.spill [r3]=f27,32 + ;; + stf.spill [r2]=f28,32 + stf.spill [r3]=f29,32 + ;; + stf.spill [r2]=f30,32 + stf.spill [r3]=f31,24 + ;; + st8.spill [r2]=r4,16 + st8.spill [r3]=r5,16 + ;; + st8.spill [r2]=r6,16 + st8.spill [r3]=r7,16 + ;; + st8 [r2]=r21,16 // save b0 + st8 [r3]=r22,16 // save b1 + /* since we're done with the spills, read and save ar.unat: */ + mov r18=ar.unat // M-unit + mov r20=ar.bspstore // M-unit + ;; + st8 [r2]=r23,16 // save b2 + st8 [r3]=r24,16 // save b3 + ;; + st8 [r2]=r25,16 // save b4 + st8 [r3]=r26,16 // save b5 + ;; + st8 [r2]=r16,16 // save ar.pfs + st8 [r3]=r17,16 // save ar.lc + mov r21=pr + ;; + st8 [r2]=r18,16 // save ar.unat + st8 [r3]=r19,16 // save ar.rnat + mov b7=r28 + ;; + st8 [r2]=r20 // save ar.bspstore + st8 [r3]=r21 // save predicate registers + mov ar.rsc=3 // put RSE back into eager mode, pl 0 + br.cond.sptk.few b7 + .endp save_switch_stack + +/* + * load_switch_stack: + * - r28 holds address to return to + */ + .align 16 + .proc load_switch_stack +load_switch_stack: + invala // invalidate ALAT + adds r2=IA64_SWITCH_STACK_B0_OFFSET+16,sp // get pointer to switch_stack.b0 + mov ar.rsc=r0 // put RSE into enforced lazy mode + adds r3=IA64_SWITCH_STACK_B0_OFFSET+24,sp // get pointer to switch_stack.b1 + ;; + ld8 r21=[r2],16 // restore b0 + ld8 r22=[r3],16 // restore b1 + ;; + ld8 r23=[r2],16 // restore b2 + ld8 r24=[r3],16 // restore b3 + ;; + ld8 r25=[r2],16 // restore b4 + ld8 r26=[r3],16 // restore b5 + ;; + ld8 r16=[r2],16 // restore ar.pfs + ld8 r17=[r3],16 // restore ar.lc + ;; + ld8 r18=[r2],16 // restore ar.unat + ld8 r19=[r3],16 // restore ar.rnat + mov b0=r21 + ;; + ld8 r20=[r2] // restore ar.bspstore + ld8 r21=[r3] // restore predicate registers + mov ar.pfs=r16 + ;; + mov ar.bspstore=r20 + ;; + loadrs // invalidate stacked regs outside current frame + adds r2=16-IA64_SWITCH_STACK_SIZE,r2 // get pointer to switch_stack.caller_unat + ;; // stop bit for rnat dependency + mov ar.rnat=r19 + mov ar.unat=r18 // establish unat holding the NaT bits for r4-r7 + adds r3=16-IA64_SWITCH_STACK_SIZE,r3 // get pointer to switch_stack.ar_fpsr + ;; + ld8 r18=[r2],16 // restore caller's unat + ld8 r19=[r3],24 // restore fpsr + mov ar.lc=r17 + ;; + ldf.fill f2=[r2],32 + ldf.fill f3=[r3],32 + mov pr=r21,-1 + ;; + ldf.fill f4=[r2],32 + ldf.fill f5=[r3],32 + ;; + ldf.fill f10=[r2],32 + ldf.fill f11=[r3],32 + mov b1=r22 + ;; + ldf.fill f12=[r2],32 + ldf.fill f13=[r3],32 + mov b2=r23 + ;; + ldf.fill f14=[r2],32 + ldf.fill f15=[r3],32 + mov b3=r24 + ;; + ldf.fill f16=[r2],32 + ldf.fill f17=[r3],32 + mov b4=r25 + ;; + ldf.fill f18=[r2],32 + ldf.fill f19=[r3],32 + mov b5=r26 + ;; + ldf.fill f20=[r2],32 + ldf.fill f21=[r3],32 + ;; + ldf.fill f22=[r2],32 + ldf.fill f23=[r3],32 + ;; + ldf.fill f24=[r2],32 + ldf.fill f25=[r3],32 + ;; + ldf.fill f26=[r2],32 + ldf.fill f27=[r3],32 + ;; + ldf.fill f28=[r2],32 + ldf.fill f29=[r3],32 + ;; + ldf.fill f30=[r2],32 + ldf.fill f31=[r3],24 + ;; + ld8.fill r4=[r2],16 + ld8.fill r5=[r3],16 + mov b7=r28 + ;; + ld8.fill r6=[r2],16 + ld8.fill r7=[r3],16 + mov ar.unat=r18 // restore caller's unat + mov ar.fpsr=r19 // restore fpsr + mov ar.rsc=3 // put RSE back into eager mode, pl 0 + adds sp=IA64_SWITCH_STACK_SIZE,sp // pop switch_stack + br.cond.sptk.few b7 + .endp load_switch_stack + + .align 16 + .global __ia64_syscall + .proc __ia64_syscall +__ia64_syscall: + .regstk 6,0,0,0 + mov r15=in5 // put syscall number in place + break __BREAK_SYSCALL + movl r2=errno + cmp.eq p6,p7=-1,r10 + ;; +(p6) st4 [r2]=r8 +(p6) mov r8=-1 + br.ret.sptk.few rp + .endp __ia64_syscall + + // + // We invoke syscall_trace through this intermediate function to + // ensure that the syscall input arguments are not clobbered. We + // also use it to preserve b6, which contains the syscall entry point. + // + .align 16 + .global invoke_syscall_trace + .proc invoke_syscall_trace +invoke_syscall_trace: + alloc loc0=ar.pfs,8,3,0,0 + ;; // WAW on CFM at the br.call + mov loc1=rp + br.call.sptk.many rp=save_switch_stack_with_current_frame // must preserve b6!! +.ret2: mov loc2=b6 + br.call.sptk.few rp=syscall_trace +.ret3: adds sp=IA64_SWITCH_STACK_SIZE,sp // drop switch_stack frame + mov rp=loc1 + mov ar.pfs=loc0 + mov b6=loc2 + ;; + br.ret.sptk.few rp + .endp invoke_syscall_trace + + // + // Invoke a system call, but do some tracing before and after the call. + // We MUST preserve the current register frame throughout this routine + // because some system calls (such as ia64_execve) directly + // manipulate ar.pfs. + // + // Input: + // r15 = syscall number + // b6 = syscall entry point + // + .global ia64_trace_syscall + .global ia64_strace_leave_kernel + .global ia64_strace_clear_r8 + + .proc ia64_strace_clear_r8 +ia64_strace_clear_r8: // this is where we return after cloning when PF_TRACESYS is on +# ifdef CONFIG_SMP + br.call.sptk.few rp=invoke_schedule_tail +# endif + mov r8=0 + br strace_check_retval + .endp ia64_strace_clear_r8 + + .proc ia64_trace_syscall +ia64_trace_syscall: + br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args +.ret4: br.call.sptk.few rp=b6 // do the syscall +strace_check_retval: +.ret5: cmp.lt p6,p0=r8,r0 // syscall failed? + ;; + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 + adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 + mov r10=0 +(p6) br.cond.sptk.few strace_error // syscall failed -> + ;; // avoid RAW on r10 +strace_save_retval: + st8.spill [r2]=r8 // store return value in slot for r8 + st8.spill [r3]=r10 // clear error indication in slot for r10 +ia64_strace_leave_kernel: + br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch return value +.ret6: br.cond.sptk.many ia64_leave_kernel + +strace_error: + ld8 r3=[r2] // load pt_regs.r8 + sub r9=0,r8 // negate return value to get errno value + ;; + cmp.ne p6,p0=r3,r0 // is pt_regs.r8!=0? + adds r3=16,r2 // r3=&pt_regs.r10 + ;; +(p6) mov r10=-1 +(p6) mov r8=r9 + br.cond.sptk.few strace_save_retval + .endp ia64_trace_syscall + +/* + * A couple of convenience macros to help implement/understand the state + * restoration that happens at the end of ia64_ret_from_syscall. + */ +#define rARPR r31 +#define rCRIFS r30 +#define rCRIPSR r29 +#define rCRIIP r28 +#define rARRSC r27 +#define rARPFS r26 +#define rARUNAT r25 +#define rARRNAT r24 +#define rARBSPSTORE r23 +#define rKRBS r22 +#define rB6 r21 + + .align 16 + .global ia64_ret_from_syscall + .global ia64_ret_from_syscall_clear_r8 + .global ia64_leave_kernel + .proc ia64_ret_from_syscall +ia64_ret_from_syscall_clear_r8: +#ifdef CONFIG_SMP + // In SMP mode, we need to call schedule_tail to complete the scheduling process. + // Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the + // address of the previously executing task. + br.call.sptk.few rp=invoke_schedule_tail +.ret7: +#endif + mov r8=0 + ;; // added stop bits to prevent r8 dependency +ia64_ret_from_syscall: + cmp.ge p6,p7=r8,r0 // syscall executed successfully? + adds r2=IA64_PT_REGS_R8_OFFSET+16,sp // r2 = &pt_regs.r8 + adds r3=IA64_PT_REGS_R8_OFFSET+32,sp // r3 = &pt_regs.r10 + ;; +(p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit +(p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit +(p7) br.cond.spnt.few handle_syscall_error // handle potential syscall failure + +ia64_leave_kernel: + // check & deliver software interrupts (bottom half handlers): + + movl r2=bh_active // sheesh, why aren't these two in + movl r3=bh_mask // a struct?? + ;; + ld8 r2=[r2] + ld8 r3=[r3] + ;; + and r2=r2,r3 + ;; + cmp.ne p6,p7=r2,r0 // any soft interrupts ready for delivery? +(p6) br.call.dpnt.few rp=invoke_do_bottom_half +1: +(pKern) br.cond.dpnt.many restore_all // yup -> skip check for rescheduling & signal delivery + + // call schedule() until we find a task that doesn't have need_resched set: + +back_from_resched: + { .mii + adds r2=IA64_TASK_NEED_RESCHED_OFFSET,r13 + mov r3=ip + adds r14=IA64_TASK_SIGPENDING_OFFSET,r13 + } + ;; + ld8 r2=[r2] + ld4 r14=[r14] + mov rp=r3 // arrange for schedule() to return to back_from_resched + ;; + /* + * If pEOI is set, we need to write the cr.eoi now and then + * clear pEOI because both invoke_schedule() and + * handle_signal_delivery() may call the scheduler. Since + * we're returning to user-level, we get at most one nested + * interrupt of the same priority level, which doesn't tax the + * kernel stack too much. + */ +(pEOI) mov cr.eoi=r0 + cmp.ne p6,p0=r2,r0 + cmp.ne p2,p0=r14,r0 // NOTE: pKern is an alias for p2!! +(pEOI) cmp.ne pEOI,p0=r0,r0 // clear pEOI before calling schedule() + srlz.d +(p6) br.call.spnt.many b6=invoke_schedule // ignore return value +2: + // check & deliver pending signals: +(p2) br.call.spnt.few rp=handle_signal_delivery +restore_all: + + // start restoring the state saved on the kernel stack (struct pt_regs): + + adds r2=IA64_PT_REGS_R8_OFFSET+16,r12 + adds r3=IA64_PT_REGS_R8_OFFSET+24,r12 + ;; + ld8.fill r8=[r2],16 + ld8.fill r9=[r3],16 + ;; + ld8.fill r10=[r2],16 + ld8.fill r11=[r3],16 + ;; + ld8.fill r16=[r2],16 + ld8.fill r17=[r3],16 + ;; + ld8.fill r18=[r2],16 + ld8.fill r19=[r3],16 + ;; + ld8.fill r20=[r2],16 + ld8.fill r21=[r3],16 + ;; + ld8.fill r22=[r2],16 + ld8.fill r23=[r3],16 + ;; + ld8.fill r24=[r2],16 + ld8.fill r25=[r3],16 + ;; + ld8.fill r26=[r2],16 + ld8.fill r27=[r3],16 + ;; + ld8.fill r28=[r2],16 + ld8.fill r29=[r3],16 + ;; + ld8.fill r30=[r2],16 + ld8.fill r31=[r3],16 + ;; + ld8 r1=[r2],16 // ar.ccv + ld8 r13=[r3],16 // ar.fpsr + ;; + ld8 r14=[r2],16 // b0 + ld8 r15=[r3],16+8 // b7 + ;; + ldf.fill f6=[r2],32 + ldf.fill f7=[r3],32 + ;; + ldf.fill f8=[r2],32 + ldf.fill f9=[r3],32 + ;; + mov ar.ccv=r1 + mov ar.fpsr=r13 + mov b0=r14 + // turn off interrupts, interrupt collection, & data translation + rsm psr.i | psr.ic | psr.dt + ;; + srlz.i // EAS 2.5 + mov b7=r15 + ;; + invala // invalidate ALAT + dep r12=0,r12,61,3 // convert sp to physical address + bsw.0;; // switch back to bank 0 (must be last in insn group) + ;; +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + nop.i 0x0 + ;; + nop.i 0x0 + ;; + nop.i 0x0 + ;; +#endif + adds r16=16,r12 + adds r17=24,r12 + ;; + ld8 rCRIPSR=[r16],16 // load cr.ipsr + ld8 rCRIIP=[r17],16 // load cr.iip + ;; + ld8 rCRIFS=[r16],16 // load cr.ifs + ld8 rARUNAT=[r17],16 // load ar.unat + ;; + ld8 rARPFS=[r16],16 // load ar.pfs + ld8 rARRSC=[r17],16 // load ar.rsc + ;; + ld8 rARRNAT=[r16],16 // load ar.rnat (may be garbage) + ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage) + ;; + ld8 rARPR=[r16],16 // load predicates + ld8 rB6=[r17],16 // load b6 + ;; + ld8 r18=[r16],16 // load ar.rsc value for "loadrs" + ld8.fill r1=[r17],16 // load r1 + ;; + ld8.fill r2=[r16],16 + ld8.fill r3=[r17],16 + ;; + ld8.fill r12=[r16],16 + ld8.fill r13=[r17],16 + extr.u r19=rCRIPSR,32,2 // extract ps.cpl + ;; + ld8.fill r14=[r16],16 + ld8.fill r15=[r17],16 + cmp.eq p6,p7=r0,r19 // are we returning to kernel mode? (psr.cpl==0) + ;; + mov b6=rB6 + mov ar.pfs=rARPFS +(p6) br.cond.dpnt.few skip_rbs_switch + + /* + * Restore user backing store. + * + * NOTE: alloc, loadrs, and cover can't be predicated. + * + * XXX This needs some scheduling/tuning once we believe it + * really does work as intended. + */ + mov r16=ar.bsp // get existing backing store pointer +(pNonSys) br.cond.dpnt.few dont_preserve_current_frame + cover // add current frame into dirty partition + ;; + mov rCRIFS=cr.ifs // fetch the cr.ifs value that "cover" produced + mov r17=ar.bsp // get new backing store pointer + ;; + sub r16=r17,r16 // calculate number of bytes that were added to rbs + ;; + shl r16=r16,16 // shift additional frame size into position for loadrs + ;; + add r18=r16,r18 // adjust the loadrs value + ;; +#ifdef CONFIG_IA64_SOFTSDV_HACKS + // Reset ITM if we've missed a timer tick. Workaround for SoftSDV bug + mov r16 = r2 + mov r2 = ar.itc + mov r17 = cr.itm + ;; + cmp.gt p6,p7 = r2, r17 +(p6) addl r17 = 100, r2 + ;; + mov cr.itm = r17 + mov r2 = r16 +#endif +dont_preserve_current_frame: + alloc r16=ar.pfs,0,0,0,0 // drop the current call frame (noop for syscalls) + ;; + mov ar.rsc=r18 // load ar.rsc to be used for "loadrs" +#ifdef CONFIG_IA32_SUPPORT + tbit.nz p6,p0=rCRIPSR,IA64_PSR_IS_BIT + ;; +(p6) mov ar.rsc=r0 // returning to IA32 mode +#endif + ;; + loadrs + ;; + mov ar.bspstore=rARBSPSTORE + ;; + mov ar.rnat=rARRNAT // must happen with RSE in lazy mode + +skip_rbs_switch: + mov ar.rsc=rARRSC + mov ar.unat=rARUNAT + mov cr.ifs=rCRIFS // restore cr.ifs only if not a (synchronous) syscall +(pEOI) mov cr.eoi=r0 + mov pr=rARPR,-1 + mov cr.iip=rCRIIP + mov cr.ipsr=rCRIPSR + ;; + rfi;; // must be last instruction in an insn group + +handle_syscall_error: + /* + * Some system calls (e.g., ptrace, mmap) can return arbitrary + * values which could lead us to mistake a negative return + * value as a failed syscall. Those syscall must deposit + * a non-zero value in pt_regs.r8 to indicate an error. + * If pt_regs.r8 is zero, we assume that the call completed + * successfully. + */ + ld8 r3=[r2] // load pt_regs.r8 + sub r9=0,r8 // negate return value to get errno + ;; + mov r10=-1 // return -1 in pt_regs.r10 to indicate error + cmp.eq p6,p7=r3,r0 // is pt_regs.r8==0? + adds r3=16,r2 // r3=&pt_regs.r10 + ;; +(p6) mov r9=r8 +(p6) mov r10=0 + ;; + st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit + st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit + br.cond.sptk.many ia64_leave_kernel + .endp __ret_from_syscall + +#ifdef CONFIG_SMP + /* + * Invoke schedule_tail(task) while preserving in0-in7, which may be needed + * in case a system call gets restarted. + */ + .proc invoke_schedule_tail +invoke_schedule_tail: + alloc loc0=ar.pfs,8,2,1,0 + mov loc1=rp + mov out0=r8 // Address of previous task + ;; + br.call.sptk.few rp=schedule_tail +.ret8: + mov ar.pfs=loc0 + mov rp=loc1 + br.ret.sptk.many rp + .endp invoke_schedule_tail +#endif /* CONFIG_SMP */ + + /* + * Invoke do_bottom_half() while preserving in0-in7, which may be needed + * in case a system call gets restarted. + */ + .proc invoke_do_bottom_half +invoke_do_bottom_half: + alloc loc0=ar.pfs,8,2,0,0 + mov loc1=rp + ;; + br.call.sptk.few rp=do_bottom_half +.ret9: + mov ar.pfs=loc0 + mov rp=loc1 + br.ret.sptk.many rp + .endp invoke_do_bottom_half + + /* + * Invoke schedule() while preserving in0-in7, which may be needed + * in case a system call gets restarted. + */ + .proc invoke_schedule +invoke_schedule: + alloc loc0=ar.pfs,8,2,0,0 + mov loc1=rp + ;; + br.call.sptk.few rp=schedule +.ret10: + mov ar.pfs=loc0 + mov rp=loc1 + br.ret.sptk.many rp + .endp invoke_schedule + + // + // Setup stack and call ia64_do_signal. Note that pSys and pNonSys need to + // be set up by the caller. We declare 8 input registers so the system call + // args get preserved, in case we need to restart a system call. + // + .align 16 + .proc handle_signal_delivery +handle_signal_delivery: + alloc loc0=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! + mov r9=ar.unat + + // If the process is being ptraced, the signal may not actually be delivered to + // the process. Instead, SIGCHLD will be sent to the parent. We need to + // setup a switch_stack so ptrace can inspect the processes state if necessary. + adds r2=IA64_TASK_FLAGS_OFFSET,r13 + ;; + ld8 r2=[r2] + mov out0=0 // there is no "oldset" + adds out1=16,sp // out1=&pt_regs + ;; +(pSys) mov out2=1 // out2==1 => we're in a syscall + tbit.nz p16,p17=r2,PF_PTRACED_BIT +(p16) br.cond.spnt.many setup_switch_stack + ;; +back_from_setup_switch_stack: +(pNonSys) mov out2=0 // out2==0 => not a syscall + adds r3=-IA64_SWITCH_STACK_SIZE+IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp +(p17) adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for (dummy) switch_stack + ;; +(p17) st8 [r3]=r9 // save ar.unat in sw->caller_unat + mov loc1=rp // save return address + br.call.sptk.few rp=ia64_do_signal +.ret11: + adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp + ;; + ld8 r9=[r3] // load new unat from sw->caller_unat + mov rp=loc1 + ;; +(p17) adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch_stack +(p17) mov ar.unat=r9 +(p17) mov ar.pfs=loc0 +(p17) br.ret.sptk.many rp + + // restore the switch stack (ptrace may have modified it): + movl r28=1f + br.cond.sptk.many load_switch_stack +1: br.ret.sptk.many rp + // NOT REACHED + +setup_switch_stack: + movl r28=back_from_setup_switch_stack + mov r16=loc0 + br.cond.sptk.many save_switch_stack + // NOT REACHED + + .endp handle_signal_delivery + + .align 16 + .proc sys_rt_sigsuspend + .global sys_rt_sigsuspend +sys_rt_sigsuspend: + alloc loc0=ar.pfs,2,2,3,0 + mov r9=ar.unat + + // If the process is being ptraced, the signal may not actually be delivered to + // the process. Instead, SIGCHLD will be sent to the parent. We need to + // setup a switch_stack so ptrace can inspect the processes state if necessary. + adds r2=IA64_TASK_FLAGS_OFFSET,r13 + ;; + ld8 r2=[r2] + mov out0=in0 // mask + mov out1=in1 // sigsetsize + ;; + adds out2=16,sp // out1=&pt_regs + tbit.nz p16,p17=r2,PF_PTRACED_BIT +(p16) br.cond.spnt.many sigsuspend_setup_switch_stack + ;; +back_from_sigsuspend_setup_switch_stack: + adds r3=-IA64_SWITCH_STACK_SIZE+IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp +(p17) adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for (dummy) switch_stack + ;; +(p17) st8 [r3]=r9 // save ar.unat in sw->caller_unat + mov loc1=rp // save return address + br.call.sptk.many rp=ia64_rt_sigsuspend +.ret12: + adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp + ;; + ld8 r9=[r3] // load new unat from sw->caller_unat + mov rp=loc1 + ;; +(p17) adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch_stack +(p17) mov ar.unat=r9 +(p17) mov ar.pfs=loc0 +(p17) br.ret.sptk.many rp + + // restore the switch stack (ptrace may have modified it): + movl r28=1f + br.cond.sptk.many load_switch_stack +1: br.ret.sptk.many rp + // NOT REACHED + +sigsuspend_setup_switch_stack: + movl r28=back_from_sigsuspend_setup_switch_stack + mov r16=loc0 + br.cond.sptk.many save_switch_stack + // NOT REACHED + + .endp sys_rt_sigsuspend + + .align 16 + .proc sys_rt_sigreturn +sys_rt_sigreturn: + alloc loc0=ar.pfs,8,1,1,0 // preserve all eight input regs in case of syscall restart! + adds out0=16,sp // out0 = &pt_regs + ;; + adds sp=-IA64_SWITCH_STACK_SIZE,sp // make space for unat and padding + br.call.sptk.few rp=ia64_rt_sigreturn +.ret13: + adds r3=IA64_SWITCH_STACK_CALLER_UNAT_OFFSET+16,sp + ;; + ld8 r9=[r3] // load new ar.unat + mov rp=r8 + ;; + adds sp=IA64_SWITCH_STACK_SIZE,sp // drop (dummy) switch-stack frame + mov ar.unat=r9 + mov ar.pfs=loc0 + br.ret.sptk.many rp + .endp sys_rt_sigreturn + + .align 16 + .global ia64_prepare_handle_unaligned + .proc ia64_prepare_handle_unaligned +ia64_prepare_handle_unaligned: + movl r28=1f + // + // r16 = fake ar.pfs, we simply need to make sure + // privilege is still 0 + // + mov r16=r0 + br.cond.sptk.few save_switch_stack +1: br.call.sptk.few rp=ia64_handle_unaligned // stack frame setup in ivt +.ret14: + movl r28=2f + br.cond.sptk.many load_switch_stack +2: br.cond.sptk.many rp // goes to ia64_leave_kernel + .endp ia64_prepare_handle_unaligned + +#ifdef CONFIG_KDB + // + // This gets called from ivt.S with: + // SAVE MIN with cover done + // SAVE REST done + // no parameters + // r15 has return value = ia64_leave_kernel + // + .align 16 + .global ia64_invoke_kdb + .proc ia64_invoke_kdb +ia64_invoke_kdb: + alloc r16=ar.pfs,0,0,4,0 + movl r28=1f // save_switch_stack protocol + ;; // avoid WAW on CFM + br.cond.sptk.many save_switch_stack // to flushrs +1: mov out0=4 // kdb entry reason + mov out1=0 // err number + adds out2=IA64_SWITCH_STACK_SIZE+16,sp // pt_regs + add out3=16,sp // switch_stack + br.call.sptk.few rp=kdb +.ret15: + movl r28=1f // load_switch_stack proto + br.cond.sptk.many load_switch_stack +1: br.ret.sptk.many rp + .endp ia64_invoke_kdb + + // + // When KDB is compiled in, we intercept each fault and give + // kdb a chance to run before calling the normal fault handler. + // + .align 16 + .global ia64_invoke_kdb_fault_handler + .proc ia64_invoke_kdb_fault_handler +ia64_invoke_kdb_fault_handler: + alloc r16=ar.pfs,5,1,5,0 + movl r28=1f + mov loc0=rp // save this + br.cond.sptk.many save_switch_stack // to flushrs + ;; // avoid WAW on CFM +1: mov out0=in0 // vector number + mov out1=in1 // cr.isr + mov out2=in2 // cr.ifa + mov out3=in3 // cr.iim + mov out4=in4 // cr.itir + br.call.sptk.few rp=ia64_kdb_fault_handler +.ret16: + + movl r28=1f + br.cond.sptk.many load_switch_stack +1: cmp.ne p6,p0=r8,r0 // did ia64_kdb_fault_handler return 0? + mov rp=loc0 +(p6) br.ret.spnt.many rp // no, we're done + ;; // avoid WAW on rp + mov out0=in0 // vector number + mov out1=in1 // cr.isr + mov out2=in2 // cr.ifa + mov out3=in3 // cr.iim + mov out4=in4 // cr.itir + mov in0=ar.pfs // preserve ar.pfs returned by load_switch_stack + br.call.sptk.few rp=ia64_fault // yup -> we need to invoke normal fault handler now +.ret17: + mov ar.pfs=in0 + mov rp=loc0 + br.ret.sptk.many rp + + .endp ia64_invoke_kdb_fault_handler + +#endif /* CONFIG_KDB */ + + .rodata + .align 8 + .globl sys_call_table +sys_call_table: + data8 sys_ni_syscall // This must be sys_ni_syscall! See ivt.S. + data8 sys_exit // 1025 + data8 sys_read + data8 sys_write + data8 sys_open + data8 sys_close + data8 sys_creat // 1030 + data8 sys_link + data8 sys_unlink + data8 ia64_execve + data8 sys_chdir + data8 sys_fchdir // 1035 + data8 sys_utimes + data8 sys_mknod + data8 sys_chmod + data8 sys_chown + data8 sys_lseek // 1040 + data8 sys_getpid + data8 sys_getppid + data8 sys_mount + data8 sys_umount + data8 sys_setuid // 1045 + data8 sys_getuid + data8 sys_geteuid + data8 sys_ptrace + data8 sys_access + data8 sys_sync // 1050 + data8 sys_fsync + data8 sys_fdatasync + data8 sys_kill + data8 sys_rename + data8 sys_mkdir // 1055 + data8 sys_rmdir + data8 sys_dup + data8 sys_pipe + data8 sys_times + data8 ia64_brk // 1060 + data8 sys_setgid + data8 sys_getgid + data8 sys_getegid + data8 sys_acct + data8 sys_ioctl // 1065 + data8 sys_fcntl + data8 sys_umask + data8 sys_chroot + data8 sys_ustat + data8 sys_dup2 // 1070 + data8 sys_setreuid + data8 sys_setregid + data8 sys_getresuid + data8 sys_setresuid + data8 sys_getresgid // 1075 + data8 sys_setresgid + data8 sys_getgroups + data8 sys_setgroups + data8 sys_getpgid + data8 sys_setpgid // 1080 + data8 sys_setsid + data8 sys_getsid + data8 sys_sethostname + data8 sys_setrlimit + data8 sys_getrlimit // 1085 + data8 sys_getrusage + data8 sys_gettimeofday + data8 sys_settimeofday + data8 sys_select + data8 sys_poll // 1090 + data8 sys_symlink + data8 sys_readlink + data8 sys_uselib + data8 sys_swapon + data8 sys_swapoff // 1095 + data8 sys_reboot + data8 sys_truncate + data8 sys_ftruncate + data8 sys_fchmod + data8 sys_fchown // 1100 + data8 ia64_getpriority + data8 sys_setpriority + data8 sys_statfs + data8 sys_fstatfs + data8 sys_ioperm // 1105 + data8 sys_semget + data8 sys_semop + data8 sys_semctl + data8 sys_msgget + data8 sys_msgsnd // 1110 + data8 sys_msgrcv + data8 sys_msgctl + data8 sys_shmget + data8 ia64_shmat + data8 sys_shmdt // 1115 + data8 sys_shmctl + data8 sys_syslog + data8 sys_setitimer + data8 sys_getitimer + data8 sys_newstat // 1120 + data8 sys_newlstat + data8 sys_newfstat + data8 sys_vhangup + data8 sys_lchown + data8 sys_vm86 // 1125 + data8 sys_wait4 + data8 sys_sysinfo + data8 sys_clone + data8 sys_setdomainname + data8 sys_newuname // 1130 + data8 sys_adjtimex + data8 sys_create_module + data8 sys_init_module + data8 sys_delete_module + data8 sys_get_kernel_syms // 1135 + data8 sys_query_module + data8 sys_quotactl + data8 sys_bdflush + data8 sys_sysfs + data8 sys_personality // 1140 + data8 ia64_ni_syscall // sys_afs_syscall + data8 sys_setfsuid + data8 sys_setfsgid + data8 sys_getdents + data8 sys_flock // 1145 + data8 sys_readv + data8 sys_writev + data8 sys_pread + data8 sys_pwrite + data8 sys_sysctl // 1150 + data8 sys_mmap + data8 sys_munmap + data8 sys_mlock + data8 sys_mlockall + data8 sys_mprotect // 1155 + data8 sys_mremap + data8 sys_msync + data8 sys_munlock + data8 sys_munlockall + data8 sys_sched_getparam // 1160 + data8 sys_sched_setparam + data8 sys_sched_getscheduler + data8 sys_sched_setscheduler + data8 sys_sched_yield + data8 sys_sched_get_priority_max // 1165 + data8 sys_sched_get_priority_min + data8 sys_sched_rr_get_interval + data8 sys_nanosleep + data8 sys_nfsservctl + data8 sys_prctl // 1170 + data8 sys_getpagesize + data8 sys_mmap2 + data8 sys_pciconfig_read + data8 sys_pciconfig_write + data8 sys_perfmonctl // 1175 + data8 sys_sigaltstack + data8 sys_rt_sigaction + data8 sys_rt_sigpending + data8 sys_rt_sigprocmask + data8 sys_rt_sigqueueinfo // 1180 + data8 sys_rt_sigreturn + data8 sys_rt_sigsuspend + data8 sys_rt_sigtimedwait + data8 sys_getcwd + data8 sys_capget // 1185 + data8 sys_capset + data8 sys_sendfile + data8 sys_ni_syscall // sys_getpmsg (STREAMS) + data8 sys_ni_syscall // sys_putpmsg (STREAMS) + data8 sys_socket // 1190 + data8 sys_bind + data8 sys_connect + data8 sys_listen + data8 sys_accept + data8 sys_getsockname // 1195 + data8 sys_getpeername + data8 sys_socketpair + data8 sys_send + data8 sys_sendto + data8 sys_recv // 1200 + data8 sys_recvfrom + data8 sys_shutdown + data8 sys_setsockopt + data8 sys_getsockopt + data8 sys_sendmsg // 1205 + data8 sys_recvmsg + data8 sys_pivot_root + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1210 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1215 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1220 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1225 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1230 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1235 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1240 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1245 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1250 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1255 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1260 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1265 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1270 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall // 1275 + data8 ia64_ni_syscall + data8 ia64_ni_syscall + data8 ia64_ni_syscall + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/entry.h linux/arch/ia64/kernel/entry.h --- v2.3.42/linux/arch/ia64/kernel/entry.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/entry.h Sun Feb 6 18:42:40 2000 @@ -0,0 +1,8 @@ +/* + * Preserved registers that are shared between code in ivt.S and entry.S. Be + * careful not to step on these! + */ +#define pEOI p1 /* should leave_kernel write EOI? */ +#define pKern p2 /* will leave_kernel return to kernel-mode? */ +#define pSys p4 /* are we processing a (synchronous) system call? */ +#define pNonSys p5 /* complement of pSys */ diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/fw-emu.c linux/arch/ia64/kernel/fw-emu.c --- v2.3.42/linux/arch/ia64/kernel/fw-emu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/fw-emu.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,444 @@ +/* + * PAL & SAL emulation. + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang + * + * For the HP simulator, this file gets include in boot/bootloader.c. + * For SoftSDV, this file gets included in sys_softsdv.c. + */ +#include + +#ifdef CONFIG_PCI +# include +#endif + +#include +#include +#include +#include + +#define MB (1024*1024UL) + +#define NUM_MEM_DESCS 3 + +static char fw_mem[( sizeof(efi_system_table_t) + + sizeof(efi_runtime_services_t) + + 1*sizeof(efi_config_table_t) + + sizeof(struct ia64_sal_systab) + + sizeof(struct ia64_sal_desc_entry_point) + + NUM_MEM_DESCS*(sizeof(efi_memory_desc_t)) + + 1024)] __attribute__ ((aligned (8))); + +#ifdef CONFIG_IA64_HP_SIM + +/* Simulator system calls: */ + +#define SSC_EXIT 66 + +/* + * Simulator system call. + */ +static long +ssc (long arg0, long arg1, long arg2, long arg3, int nr) +{ + register long r8 asm ("r8"); + + asm volatile ("mov r15=%1\n\t" + "break 0x80001" + : "=r"(r8) + : "r"(nr), "r"(arg0), "r"(arg1), "r"(arg2), "r"(arg3)); + return r8; +} + +#define SECS_PER_HOUR (60 * 60) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) + +/* Compute the `struct tm' representation of *T, + offset OFFSET seconds east of UTC, + and store year, yday, mon, mday, wday, hour, min, sec into *TP. + Return nonzero if successful. */ +int +offtime (unsigned long t, efi_time_t *tp) +{ + const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + long int days, rem, y; + const unsigned short int *ip; + + days = t / SECS_PER_DAY; + rem = t % SECS_PER_DAY; + while (rem < 0) { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) { + rem -= SECS_PER_DAY; + ++days; + } + tp->hour = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + tp->minute = rem / 60; + tp->second = rem % 60; + /* January 1, 1970 was a Thursday. */ + y = 1970; + +# define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) +# define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) +# define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + + while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { + /* Guess a corrected year, assuming 365 days per year. */ + long int yg = y + days / 365 - (days % 365 < 0); + + /* Adjust DAYS and Y to match the guessed year. */ + days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) + - LEAPS_THRU_END_OF (y - 1)); + y = yg; + } + tp->year = y; + ip = __mon_yday[__isleap(y)]; + for (y = 11; days < (long int) ip[y]; --y) + continue; + days -= ip[y]; + tp->month = y + 1; + tp->day = days + 1; + return 1; +} + +#endif /* CONFIG_IA64_HP_SIM */ + +/* + * Very ugly, but we need this in the simulator only. Once we run on + * real hw, this can all go away. + */ +extern void pal_emulator_static (void); + +asm (" + .proc pal_emulator_static +pal_emulator_static: + mov r8=-1 + cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ +(p7) br.cond.sptk.few 1f + ;; + mov r8=0 /* status = 0 */ + movl r9=0x100000000 /* tc.base */ + movl r10=0x0000000200000003 /* count[0], count[1] */ + movl r11=0x1000000000002000 /* stride[0], stride[1] */ + br.cond.sptk.few rp + +1: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */ +(p7) br.cond.sptk.few 1f + mov r8=0 /* status = 0 */ + movl r9 =0x100000064 /* proc_ratio (1/100) */ + movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ + movl r11=0x100000064 /* itc_ratio<<32 (1/100) */ +1: br.cond.sptk.few rp + .endp pal_emulator_static\n"); + +/* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */ + +#define BUILD_CMD(addr) ((0x80000000 | (addr)) & ~3) + +#define REG_OFFSET(addr) (0x00000000000000FF & (addr)) +#define DEVICE_FUNCTION(addr) (0x000000000000FF00 & (addr)) +#define BUS_NUMBER(addr) (0x0000000000FF0000 & (addr)) + +static efi_status_t +efi_get_time (efi_time_t *tm, efi_time_cap_t *tc) +{ +#ifdef CONFIG_IA64_HP_SIM + struct { + int tv_sec; /* must be 32bits to work */ + int tv_usec; + } tv32bits; + + ssc((unsigned long) &tv32bits, 0, 0, 0, SSC_GET_TOD); + + memset(tm, 0, sizeof(*tm)); + offtime(tv32bits.tv_sec, tm); + + if (tc) + memset(tc, 0, sizeof(*tc)); +#else +# error Not implemented yet... +#endif + return EFI_SUCCESS; +} + +static void +efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data) +{ +#ifdef CONFIG_IA64_HP_SIM + ssc(status, 0, 0, 0, SSC_EXIT); +#else +# error Not implemented yet... +#endif +} + +static efi_status_t +efi_unimplemented (void) +{ + return EFI_UNSUPPORTED; +} + +static long +sal_emulator (long index, unsigned long in1, unsigned long in2, + unsigned long in3, unsigned long in4, unsigned long in5, + unsigned long in6, unsigned long in7) +{ + register long r9 asm ("r9") = 0; + register long r10 asm ("r10") = 0; + register long r11 asm ("r11") = 0; + long status; + + /* + * Don't do a "switch" here since that gives us code that + * isn't self-relocatable. + */ + status = 0; + if (index == SAL_FREQ_BASE) { + switch (in1) { + case SAL_FREQ_BASE_PLATFORM: + r9 = 100000000; + break; + + case SAL_FREQ_BASE_INTERVAL_TIMER: + /* + * Is this supposed to be the cr.itc frequency + * or something platform specific? The SAL + * doc ain't exactly clear on this... + */ +#if defined(CONFIG_IA64_SOFTSDV_HACKS) + r9 = 4000000; +#elif defined(CONFIG_IA64_SDV) + r9 = 300000000; +#else + r9 = 700000000; +#endif + break; + + case SAL_FREQ_BASE_REALTIME_CLOCK: + r9 = 1; + break; + + default: + status = -1; + break; + } + } else if (index == SAL_SET_VECTORS) { + ; + } else if (index == SAL_GET_STATE_INFO) { + ; + } else if (index == SAL_GET_STATE_INFO_SIZE) { + ; + } else if (index == SAL_CLEAR_STATE_INFO) { + ; + } else if (index == SAL_MC_RENDEZ) { + ; + } else if (index == SAL_MC_SET_PARAMS) { + ; + } else if (index == SAL_CACHE_FLUSH) { + ; + } else if (index == SAL_CACHE_INIT) { + ; +#ifdef CONFIG_PCI + } else if (index == SAL_PCI_CONFIG_READ) { + /* + * in1 contains the PCI configuration address and in2 + * the size of the read. The value that is read is + * returned via the general register r9. + */ + outl(BUILD_CMD(in1), 0xCF8); + if (in2 == 1) /* Reading byte */ + r9 = inb(0xCFC + ((REG_OFFSET(in1) & 3))); + else if (in2 == 2) /* Reading word */ + r9 = inw(0xCFC + ((REG_OFFSET(in1) & 2))); + else /* Reading dword */ + r9 = inl(0xCFC); + status = PCIBIOS_SUCCESSFUL; + } else if (index == SAL_PCI_CONFIG_WRITE) { + /* + * in1 contains the PCI configuration address, in2 the + * size of the write, and in3 the actual value to be + * written out. + */ + outl(BUILD_CMD(in1), 0xCF8); + if (in2 == 1) /* Writing byte */ + outb(in3, 0xCFC + ((REG_OFFSET(in1) & 3))); + else if (in2 == 2) /* Writing word */ + outw(in3, 0xCFC + ((REG_OFFSET(in1) & 2))); + else /* Writing dword */ + outl(in3, 0xCFC); + status = PCIBIOS_SUCCESSFUL; +#endif /* CONFIG_PCI */ + } else if (index == SAL_UPDATE_PAL) { + ; + } else { + status = -1; + } + asm volatile ("" :: "r"(r9), "r"(r10), "r"(r11)); + return status; +} + + +/* + * This is here to work around a bug in egcs-1.1.1b that causes the + * compiler to crash (seems like a bug in the new alias analysis code. + */ +void * +id (long addr) +{ + return (void *) addr; +} + +void +sys_fw_init (const char *args, int arglen) +{ + efi_system_table_t *efi_systab; + efi_runtime_services_t *efi_runtime; + efi_config_table_t *efi_tables; + struct ia64_sal_systab *sal_systab; + efi_memory_desc_t *efi_memmap, *md; + unsigned long *pal_desc, *sal_desc; + struct ia64_sal_desc_entry_point *sal_ed; + struct ia64_boot_param *bp; + unsigned char checksum = 0; + char *cp, *cmd_line; + + memset(fw_mem, 0, sizeof(fw_mem)); + + pal_desc = (unsigned long *) &pal_emulator_static; + sal_desc = (unsigned long *) &sal_emulator; + + cp = fw_mem; + efi_systab = (void *) cp; cp += sizeof(*efi_systab); + efi_runtime = (void *) cp; cp += sizeof(*efi_runtime); + efi_tables = (void *) cp; cp += sizeof(*efi_tables); + sal_systab = (void *) cp; cp += sizeof(*sal_systab); + sal_ed = (void *) cp; cp += sizeof(*sal_ed); + efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap); + cmd_line = (void *) cp; + + if (args) { + if (arglen >= 1024) + arglen = 1023; + memcpy(cmd_line, args, arglen); + } else { + arglen = 0; + } + cmd_line[arglen] = '\0'; + + memset(efi_systab, 0, sizeof(efi_systab)); + efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; + efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION; + efi_systab->hdr.headersize = sizeof(efi_systab->hdr); + efi_systab->fw_vendor = __pa("H\0e\0w\0l\0e\0t\0t\0-\0P\0a\0c\0k\0a\0r\0d\0\0"); + efi_systab->fw_revision = 1; + efi_systab->runtime = __pa(efi_runtime); + efi_systab->nr_tables = 1; + efi_systab->tables = __pa(efi_tables); + + efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE; + efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION; + efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr); + efi_runtime->get_time = __pa(&efi_get_time); + efi_runtime->set_time = __pa(&efi_unimplemented); + efi_runtime->get_wakeup_time = __pa(&efi_unimplemented); + efi_runtime->set_wakeup_time = __pa(&efi_unimplemented); + efi_runtime->set_virtual_address_map = __pa(&efi_unimplemented); + efi_runtime->get_variable = __pa(&efi_unimplemented); + efi_runtime->get_next_variable = __pa(&efi_unimplemented); + efi_runtime->set_variable = __pa(&efi_unimplemented); + efi_runtime->get_next_high_mono_count = __pa(&efi_unimplemented); + efi_runtime->reset_system = __pa(&efi_reset_system); + + efi_tables->guid = SAL_SYSTEM_TABLE_GUID; + efi_tables->table = __pa(sal_systab); + + /* fill in the SAL system table: */ + memcpy(sal_systab->signature, "SST_", 4); + sal_systab->size = sizeof(*sal_systab); + sal_systab->sal_rev_minor = 1; + sal_systab->sal_rev_major = 0; + sal_systab->entry_count = 1; + sal_systab->ia32_bios_present = 0; + +#ifdef CONFIG_IA64_GENERIC + strcpy(sal_systab->oem_id, "Generic"); + strcpy(sal_systab->product_id, "IA-64 system"); +#endif + +#ifdef CONFIG_IA64_HP_SIM + strcpy(sal_systab->oem_id, "Hewlett-Packard"); + strcpy(sal_systab->product_id, "HP-simulator"); +#endif + +#ifdef CONFIG_IA64_SDV + strcpy(sal_systab->oem_id, "Intel"); + strcpy(sal_systab->product_id, "SDV"); +#endif + +#ifdef CONFIG_IA64_SGI_SN1_SIM + strcpy(sal_systab->oem_id, "SGI"); + strcpy(sal_systab->product_id, "SN1"); +#endif + + /* fill in an entry point: */ + sal_ed->type = SAL_DESC_ENTRY_POINT; + sal_ed->pal_proc = __pa(pal_desc[0]); + sal_ed->sal_proc = __pa(sal_desc[0]); + sal_ed->gp = __pa(sal_desc[1]); + + for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp) + checksum += *cp; + + sal_systab->checksum = -checksum; + + /* fill in a memory descriptor: */ + md = &efi_memmap[0]; + md->type = EFI_CONVENTIONAL_MEMORY; + md->pad = 0; + md->phys_addr = 2*MB; + md->virt_addr = 0; + md->num_pages = (64*MB) >> 12; /* 64MB (in 4KB pages) */ + md->attribute = EFI_MEMORY_WB; + + /* descriptor for firmware emulator: */ + md = &efi_memmap[1]; + md->type = EFI_RUNTIME_SERVICES_DATA; + md->pad = 0; + md->phys_addr = 1*MB; + md->virt_addr = 0; + md->num_pages = (1*MB) >> 12; /* 1MB (in 4KB pages) */ + md->attribute = EFI_MEMORY_WB; + + /* descriptor for high memory (>4GB): */ + md = &efi_memmap[2]; + md->type = EFI_CONVENTIONAL_MEMORY; + md->pad = 0; + md->phys_addr = 4096*MB; + md->virt_addr = 0; + md->num_pages = (32*MB) >> 12; /* 32MB (in 4KB pages) */ + md->attribute = EFI_MEMORY_WB; + + bp = id(ZERO_PAGE_ADDR); + bp->efi_systab = __pa(&fw_mem); + bp->efi_memmap = __pa(efi_memmap); + bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t); + bp->efi_memdesc_size = sizeof(efi_memory_desc_t); + bp->efi_memdesc_version = 1; + bp->command_line = __pa(cmd_line); + bp->console_info.num_cols = 80; + bp->console_info.num_rows = 25; + bp->console_info.orig_x = 0; + bp->console_info.orig_y = 24; + bp->num_pci_vectors = 0; + bp->fpswa = 0; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S --- v2.3.42/linux/arch/ia64/kernel/gate.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/gate.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,200 @@ +/* + * This file contains the code that gets mapped at the upper end of + * each task's text region. For now, it contains the signal + * trampoline code only. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + */ + +#include +#include +#include +#include +#include + + .psr abi64 + .psr lsb + .lsb + + .section __gate_section,"ax" + + .align PAGE_SIZE + +# define SIGINFO_OFF 16 +# define SIGCONTEXT_OFF (SIGINFO_OFF + ((IA64_SIGINFO_SIZE + 15) & ~15)) +# define FLAGS_OFF IA64_SIGCONTEXT_FLAGS_OFFSET +# define CFM_OFF IA64_SIGCONTEXT_CFM_OFFSET +# define FR6_OFF IA64_SIGCONTEXT_FR6_OFFSET +# define BSP_OFF IA64_SIGCONTEXT_AR_BSP_OFFSET +# define RNAT_OFF IA64_SIGCONTEXT_AR_RNAT_OFFSET +# define base0 r2 +# define base1 r3 + /* + * When we get here, the memory stack looks like this: + * + * +===============================+ + * | | + * // struct sigcontext // + * | | + * +===============================+ <-- sp+SIGCONTEXT_OFF + * | | + * // rest of siginfo // + * | | + * + +---------------+ + * | | siginfo.code | + * +---------------+---------------+ + * | siginfo.errno | siginfo.signo | + * +-------------------------------+ <-- sp+SIGINFO_OFF + * | 16 byte of scratch | + * | space | + * +-------------------------------+ <-- sp + * + * The register stack looks _exactly_ the way it looked at the + * time the signal occurred. In other words, we're treading + * on a potential mine-field: each incoming general register + * may be a NaT value (includeing sp, in which case the process + * ends up dying with a SIGSEGV). + * + * The first need to do is a cover to get the registers onto + * the backing store. Once that is done, we invoke the signal + * handler which may modify some of the machine state. After + * returning from the signal handler, we return control to the + * previous context by executing a sigreturn system call. A + * signal handler may call the rt_sigreturn() function to + * directly return to a given sigcontext. However, the + * user-level sigreturn() needs to do much more than calling + * the rt_sigreturn() system call as it needs to unwind the + * stack to restore preserved registers that may have been + * saved on the signal handler's call stack. + * + * On entry: + * r2 = signal number + * r3 = plabel of signal handler + * r15 = new register backing store (ignored) + * [sp+16] = sigframe + */ + + .global ia64_sigtramp + .proc ia64_sigtramp +ia64_sigtramp: + ld8 r10=[r3],8 // get signal handler entry point + br.call.sptk.many rp=invoke_sighandler +.ret0: mov r15=__NR_rt_sigreturn + break __BREAK_SYSCALL + .endp ia64_sigramp + + .proc invoke_sighandler +invoke_sighandler: + ld8 gp=[r3] // get signal handler's global pointer + mov b6=r10 + cover // push args in interrupted frame onto backing store + ;; + alloc r8=ar.pfs,0,1,3,0 // get CFM0, EC0, and CPL0 into r8 + mov r17=ar.bsp // fetch ar.bsp + mov loc0=rp // save return pointer + ;; + cmp.ne p8,p0=r15,r0 // do we need to switch the rbs? + mov out0=r2 // signal number +(p8) br.cond.spnt.few setup_rbs // yup -> (clobbers r14 and r16) +back_from_setup_rbs: + adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp + ;; + st8 [base0]=r17,(CFM_OFF-BSP_OFF) // save sc_ar_bsp + adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp + ;; + + st8 [base0]=r8 // save CFM0, EC0, and CPL0 + adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp + ;; + stf.spill [base0]=f6,32 + stf.spill [base1]=f7,32 + ;; + stf.spill [base0]=f8,32 + stf.spill [base1]=f9,32 + ;; + stf.spill [base0]=f10,32 + stf.spill [base1]=f11,32 + adds out1=SIGINFO_OFF,sp // siginfo pointer + ;; + stf.spill [base0]=f12,32 + stf.spill [base1]=f13,32 + adds out2=SIGCONTEXT_OFF,sp // sigcontext pointer + ;; + stf.spill [base0]=f14,32 + stf.spill [base1]=f15,32 + br.call.sptk.few rp=b6 // call the signal handler +.ret2: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp + ;; + ld8 r15=[base0],(CFM_OFF-BSP_OFF) // fetch sc_ar_bsp and advance to CFM_OFF + mov r14=ar.bsp + ;; + ld8 r8=[base0] // restore (perhaps modified) CFM0, EC0, and CPL0 + cmp.ne p8,p0=r14,r15 // do we need to restore the rbs? +(p8) br.cond.spnt.few restore_rbs // yup -> (clobbers r14 and r16) +back_from_restore_rbs: + { + and r9=0x7f,r8 // r9 <- CFM0.sof + extr.u r10=r8,7,7 // r10 <- CFM0.sol + mov r11=ip + } + ;; + adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp + adds r11=(cont-back_from_restore_rbs),r11 + sub r9=r9,r10 // r9 <- CFM0.sof - CFM0.sol == CFM0.nout + ;; + adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp + dep r9=r9,r9,7,7 // r9.sol = r9.sof + mov b6=r11 + ;; + ldf.fill f6=[base0],32 + ldf.fill f7=[base1],32 + mov rp=loc0 // copy return pointer out of stacked register + ;; + ldf.fill f8=[base0],32 + ldf.fill f9=[base1],32 + ;; + ldf.fill f10=[base0],32 + ldf.fill f11=[base1],32 + ;; + ldf.fill f12=[base0],32 + ldf.fill f13=[base1],32 + mov ar.pfs=r9 + ;; + ldf.fill f14=[base0],32 + ldf.fill f15=[base1],32 + br.ret.sptk.few b6 +cont: mov ar.pfs=r8 // ar.pfs = CFM0 + br.ret.sptk.few rp // re-establish CFM0 + .endp invoke_signal_handler + + .proc setup_rbs +setup_rbs: + flushrs // must be first in insn + ;; + mov ar.rsc=r0 // put RSE into enforced lazy mode + adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp + mov r14=ar.rnat // get rnat as updated by flushrs + ;; + mov ar.bspstore=r15 // set new register backing store area + st8 [r16]=r14 // save sc_ar_rnat + ;; + mov ar.rsc=0xf // set RSE into eager mode, pl 3 + invala // invalidate ALAT + br.cond.sptk.many back_from_setup_rbs + + .proc restore_rbs +restore_rbs: + flushrs + mov ar.rsc=r0 // put RSE into enforced lazy mode + adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp + ;; + ld8 r14=[r16] // get new rnat + mov ar.bspstore=r15 // set old register backing store area + ;; + mov ar.rnat=r14 // establish new rnat + mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) + // invala not necessary as that will happen when returning to user-mode + br.cond.sptk.many back_from_restore_rbs + + .endp restore_rbs diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S --- v2.3.42/linux/arch/ia64/kernel/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/head.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,646 @@ +/* + * Here is where the ball gets rolling as far as the kernel is concerned. + * When control is transferred to _start, the bootload has already + * loaded us to the correct address. All that's left to do here is + * to set up the kernel's global pointer and jump to the kernel + * entry point. + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999 Intel Corp. + * Copyright (C) 1999 Asit Mallick + * Copyright (C) 1999 Don Dugger + */ + +#include + +#include +#include +#include +#include +#include +#include + + .psr abi64 + .psr lsb + .lsb + + .section __special_page_section,"ax" + + .global empty_zero_page +empty_zero_page: + .skip PAGE_SIZE + + .global swapper_pg_dir +swapper_pg_dir: + .skip PAGE_SIZE + + .global empty_bad_page +empty_bad_page: + .skip PAGE_SIZE + + .global empty_bad_pte_table +empty_bad_pte_table: + .skip PAGE_SIZE + + .global empty_bad_pmd_table +empty_bad_pmd_table: + .skip PAGE_SIZE + + .rodata +halt_msg: + stringz "Halting kernel\n" + + .text + .align 16 + .global _start + .proc _start +_start: + // set IVT entry point---can't access I/O ports without it + movl r3=ia64_ivt + ;; + mov cr.iva=r3 + movl r2=FPSR_DEFAULT + ;; + srlz.i + movl gp=__gp + + mov ar.fpsr=r2 + ;; + +#ifdef CONFIG_IA64_EARLY_PRINTK + mov r2=6 + mov r3=(8<<8) | (28<<2) + ;; + mov rr[r2]=r3 + ;; + srlz.i + ;; +#endif + +#define isAP p2 // are we booting an Application Processor (not the BSP)? + + // Find the init_task for the currently booting CPU. At poweron, and in + // UP mode, cpu_now_booting is 0 + movl r3=cpu_now_booting + ;; + ld4 r3=[r3] + movl r2=init_tasks + ;; + shladd r2=r3,3,r2 + ;; + ld8 r2=[r2] + cmp4.ne isAP,p0=r3,r0 // p9 == true if this is an application processor (ap) + ;; // RAW on r2 + extr r3=r2,0,61 // r3 == phys addr of task struct + ;; + + // load the "current" pointer (r13) and ar.k6 with the current task + mov r13=r2 + mov ar.k6=r3 // Physical address + ;; + /* + * Reserve space at the top of the stack for "struct pt_regs". Kernel threads + * don't store interesting values in that structure, but the space still needs + * to be there because time-critical stuff such as the context switching can + * be implemented more efficiently (for example, __switch_to() + * always sets the psr.dfh bit of the task it is switching to). + */ + addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 + addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE + mov ar.rsc=r0 // place RSE in enforced lazy mode + ;; + mov ar.bspstore=r2 // establish the new RSE stack + ;; + loadrs // load zero bytes from the register stack + ;; + mov ar.rsc=0x3 // place RSE in eager mode + ;; + +#ifdef CONFIG_IA64_EARLY_PRINTK + .rodata +alive_msg: + stringz "I'm alive and well\n" + .previous + + alloc r2=ar.pfs,0,0,2,0 + movl out0=alive_msg + ;; + br.call.sptk.few rp=early_printk +1: // force new bundle +#endif /* CONFIG_IA64_EARLY_PRINTK */ + + alloc r2=ar.pfs,8,0,2,0 +#ifdef CONFIG_SMP +(isAP) br.call.sptk.few rp=smp_callin +.ret1: +(isAP) br.cond.sptk.few self +#endif + +#undef isAP + + // This is executed by the bootstrap processor (bsp) only: + +#ifdef CONFIG_IA64_FW_EMU + // initialize PAL & SAL emulator: + br.call.sptk.few rp=sys_fw_init + ;; +#endif + br.call.sptk.few rp=start_kernel +.ret2: + addl r2=@ltoff(halt_msg),gp + ;; + ld8 out0=[r2] + br.call.sptk.few b0=console_print +self: br.sptk.few self // endless loop + .endp _start + + .align 16 + .global ia64_save_debug_regs + .proc ia64_save_debug_regs +ia64_save_debug_regs: + alloc r16=ar.pfs,1,0,0,0 + mov r20=ar.lc // preserve ar.lc + mov ar.lc=IA64_NUM_DBG_REGS-1 + mov r18=0 + add r19=IA64_NUM_DBG_REGS*8,in0 + ;; +1: mov r16=dbr[r18] + mov r17=ibr[r18] + add r18=1,r18 + ;; + st8.nta [in0]=r16,8 + st8.nta [r19]=r17,8 + br.cloop.sptk.few 1b + + mov ar.lc=r20 // restore ar.lc + br.ret.sptk.few b0 + .endp ia64_save_debug_regs + + .align 16 + .global ia64_load_debug_regs + .proc ia64_load_debug_regs +ia64_load_debug_regs: + alloc r16=ar.pfs,1,0,0,0 + lfetch.nta [in0] + mov r20=ar.lc // preserve ar.lc + add r19=IA64_NUM_DBG_REGS*8,in0 + mov ar.lc=IA64_NUM_DBG_REGS-1 + mov r18=-1 + ;; +1: ld8.nta r16=[in0],8 + ld8.nta r17=[r19],8 + add r18=1,r18 + ;; + mov dbr[r18]=r16 + mov ibr[r18]=r17 + br.cloop.sptk.few 1b + + mov ar.lc=r20 // restore ar.lc + br.ret.sptk.few b0 + .endp ia64_load_debug_regs + + .align 16 + .global __ia64_save_fpu + .proc __ia64_save_fpu +__ia64_save_fpu: + alloc r2=ar.pfs,1,0,0,0 + adds r3=16,in0 + ;; + stf.spill.nta [in0]=f32,32 + stf.spill.nta [ r3]=f33,32 + ;; + stf.spill.nta [in0]=f34,32 + stf.spill.nta [ r3]=f35,32 + ;; + stf.spill.nta [in0]=f36,32 + stf.spill.nta [ r3]=f37,32 + ;; + stf.spill.nta [in0]=f38,32 + stf.spill.nta [ r3]=f39,32 + ;; + stf.spill.nta [in0]=f40,32 + stf.spill.nta [ r3]=f41,32 + ;; + stf.spill.nta [in0]=f42,32 + stf.spill.nta [ r3]=f43,32 + ;; + stf.spill.nta [in0]=f44,32 + stf.spill.nta [ r3]=f45,32 + ;; + stf.spill.nta [in0]=f46,32 + stf.spill.nta [ r3]=f47,32 + ;; + stf.spill.nta [in0]=f48,32 + stf.spill.nta [ r3]=f49,32 + ;; + stf.spill.nta [in0]=f50,32 + stf.spill.nta [ r3]=f51,32 + ;; + stf.spill.nta [in0]=f52,32 + stf.spill.nta [ r3]=f53,32 + ;; + stf.spill.nta [in0]=f54,32 + stf.spill.nta [ r3]=f55,32 + ;; + stf.spill.nta [in0]=f56,32 + stf.spill.nta [ r3]=f57,32 + ;; + stf.spill.nta [in0]=f58,32 + stf.spill.nta [ r3]=f59,32 + ;; + stf.spill.nta [in0]=f60,32 + stf.spill.nta [ r3]=f61,32 + ;; + stf.spill.nta [in0]=f62,32 + stf.spill.nta [ r3]=f63,32 + ;; + stf.spill.nta [in0]=f64,32 + stf.spill.nta [ r3]=f65,32 + ;; + stf.spill.nta [in0]=f66,32 + stf.spill.nta [ r3]=f67,32 + ;; + stf.spill.nta [in0]=f68,32 + stf.spill.nta [ r3]=f69,32 + ;; + stf.spill.nta [in0]=f70,32 + stf.spill.nta [ r3]=f71,32 + ;; + stf.spill.nta [in0]=f72,32 + stf.spill.nta [ r3]=f73,32 + ;; + stf.spill.nta [in0]=f74,32 + stf.spill.nta [ r3]=f75,32 + ;; + stf.spill.nta [in0]=f76,32 + stf.spill.nta [ r3]=f77,32 + ;; + stf.spill.nta [in0]=f78,32 + stf.spill.nta [ r3]=f79,32 + ;; + stf.spill.nta [in0]=f80,32 + stf.spill.nta [ r3]=f81,32 + ;; + stf.spill.nta [in0]=f82,32 + stf.spill.nta [ r3]=f83,32 + ;; + stf.spill.nta [in0]=f84,32 + stf.spill.nta [ r3]=f85,32 + ;; + stf.spill.nta [in0]=f86,32 + stf.spill.nta [ r3]=f87,32 + ;; + stf.spill.nta [in0]=f88,32 + stf.spill.nta [ r3]=f89,32 + ;; + stf.spill.nta [in0]=f90,32 + stf.spill.nta [ r3]=f91,32 + ;; + stf.spill.nta [in0]=f92,32 + stf.spill.nta [ r3]=f93,32 + ;; + stf.spill.nta [in0]=f94,32 + stf.spill.nta [ r3]=f95,32 + ;; + stf.spill.nta [in0]=f96,32 + stf.spill.nta [ r3]=f97,32 + ;; + stf.spill.nta [in0]=f98,32 + stf.spill.nta [ r3]=f99,32 + ;; + stf.spill.nta [in0]=f100,32 + stf.spill.nta [ r3]=f101,32 + ;; + stf.spill.nta [in0]=f102,32 + stf.spill.nta [ r3]=f103,32 + ;; + stf.spill.nta [in0]=f104,32 + stf.spill.nta [ r3]=f105,32 + ;; + stf.spill.nta [in0]=f106,32 + stf.spill.nta [ r3]=f107,32 + ;; + stf.spill.nta [in0]=f108,32 + stf.spill.nta [ r3]=f109,32 + ;; + stf.spill.nta [in0]=f110,32 + stf.spill.nta [ r3]=f111,32 + ;; + stf.spill.nta [in0]=f112,32 + stf.spill.nta [ r3]=f113,32 + ;; + stf.spill.nta [in0]=f114,32 + stf.spill.nta [ r3]=f115,32 + ;; + stf.spill.nta [in0]=f116,32 + stf.spill.nta [ r3]=f117,32 + ;; + stf.spill.nta [in0]=f118,32 + stf.spill.nta [ r3]=f119,32 + ;; + stf.spill.nta [in0]=f120,32 + stf.spill.nta [ r3]=f121,32 + ;; + stf.spill.nta [in0]=f122,32 + stf.spill.nta [ r3]=f123,32 + ;; + stf.spill.nta [in0]=f124,32 + stf.spill.nta [ r3]=f125,32 + ;; + stf.spill.nta [in0]=f126,32 + stf.spill.nta [ r3]=f127,32 + br.ret.sptk.few rp + .endp __ia64_save_fpu + + .align 16 + .global __ia64_load_fpu + .proc __ia64_load_fpu +__ia64_load_fpu: + alloc r2=ar.pfs,1,0,0,0 + adds r3=16,in0 + ;; + ldf.fill.nta f32=[in0],32 + ldf.fill.nta f33=[ r3],32 + ;; + ldf.fill.nta f34=[in0],32 + ldf.fill.nta f35=[ r3],32 + ;; + ldf.fill.nta f36=[in0],32 + ldf.fill.nta f37=[ r3],32 + ;; + ldf.fill.nta f38=[in0],32 + ldf.fill.nta f39=[ r3],32 + ;; + ldf.fill.nta f40=[in0],32 + ldf.fill.nta f41=[ r3],32 + ;; + ldf.fill.nta f42=[in0],32 + ldf.fill.nta f43=[ r3],32 + ;; + ldf.fill.nta f44=[in0],32 + ldf.fill.nta f45=[ r3],32 + ;; + ldf.fill.nta f46=[in0],32 + ldf.fill.nta f47=[ r3],32 + ;; + ldf.fill.nta f48=[in0],32 + ldf.fill.nta f49=[ r3],32 + ;; + ldf.fill.nta f50=[in0],32 + ldf.fill.nta f51=[ r3],32 + ;; + ldf.fill.nta f52=[in0],32 + ldf.fill.nta f53=[ r3],32 + ;; + ldf.fill.nta f54=[in0],32 + ldf.fill.nta f55=[ r3],32 + ;; + ldf.fill.nta f56=[in0],32 + ldf.fill.nta f57=[ r3],32 + ;; + ldf.fill.nta f58=[in0],32 + ldf.fill.nta f59=[ r3],32 + ;; + ldf.fill.nta f60=[in0],32 + ldf.fill.nta f61=[ r3],32 + ;; + ldf.fill.nta f62=[in0],32 + ldf.fill.nta f63=[ r3],32 + ;; + ldf.fill.nta f64=[in0],32 + ldf.fill.nta f65=[ r3],32 + ;; + ldf.fill.nta f66=[in0],32 + ldf.fill.nta f67=[ r3],32 + ;; + ldf.fill.nta f68=[in0],32 + ldf.fill.nta f69=[ r3],32 + ;; + ldf.fill.nta f70=[in0],32 + ldf.fill.nta f71=[ r3],32 + ;; + ldf.fill.nta f72=[in0],32 + ldf.fill.nta f73=[ r3],32 + ;; + ldf.fill.nta f74=[in0],32 + ldf.fill.nta f75=[ r3],32 + ;; + ldf.fill.nta f76=[in0],32 + ldf.fill.nta f77=[ r3],32 + ;; + ldf.fill.nta f78=[in0],32 + ldf.fill.nta f79=[ r3],32 + ;; + ldf.fill.nta f80=[in0],32 + ldf.fill.nta f81=[ r3],32 + ;; + ldf.fill.nta f82=[in0],32 + ldf.fill.nta f83=[ r3],32 + ;; + ldf.fill.nta f84=[in0],32 + ldf.fill.nta f85=[ r3],32 + ;; + ldf.fill.nta f86=[in0],32 + ldf.fill.nta f87=[ r3],32 + ;; + ldf.fill.nta f88=[in0],32 + ldf.fill.nta f89=[ r3],32 + ;; + ldf.fill.nta f90=[in0],32 + ldf.fill.nta f91=[ r3],32 + ;; + ldf.fill.nta f92=[in0],32 + ldf.fill.nta f93=[ r3],32 + ;; + ldf.fill.nta f94=[in0],32 + ldf.fill.nta f95=[ r3],32 + ;; + ldf.fill.nta f96=[in0],32 + ldf.fill.nta f97=[ r3],32 + ;; + ldf.fill.nta f98=[in0],32 + ldf.fill.nta f99=[ r3],32 + ;; + ldf.fill.nta f100=[in0],32 + ldf.fill.nta f101=[ r3],32 + ;; + ldf.fill.nta f102=[in0],32 + ldf.fill.nta f103=[ r3],32 + ;; + ldf.fill.nta f104=[in0],32 + ldf.fill.nta f105=[ r3],32 + ;; + ldf.fill.nta f106=[in0],32 + ldf.fill.nta f107=[ r3],32 + ;; + ldf.fill.nta f108=[in0],32 + ldf.fill.nta f109=[ r3],32 + ;; + ldf.fill.nta f110=[in0],32 + ldf.fill.nta f111=[ r3],32 + ;; + ldf.fill.nta f112=[in0],32 + ldf.fill.nta f113=[ r3],32 + ;; + ldf.fill.nta f114=[in0],32 + ldf.fill.nta f115=[ r3],32 + ;; + ldf.fill.nta f116=[in0],32 + ldf.fill.nta f117=[ r3],32 + ;; + ldf.fill.nta f118=[in0],32 + ldf.fill.nta f119=[ r3],32 + ;; + ldf.fill.nta f120=[in0],32 + ldf.fill.nta f121=[ r3],32 + ;; + ldf.fill.nta f122=[in0],32 + ldf.fill.nta f123=[ r3],32 + ;; + ldf.fill.nta f124=[in0],32 + ldf.fill.nta f125=[ r3],32 + ;; + ldf.fill.nta f126=[in0],32 + ldf.fill.nta f127=[ r3],32 + br.ret.sptk.few rp + .endp __ia64_load_fpu + + .align 16 + .global __ia64_init_fpu + .proc __ia64_init_fpu +__ia64_init_fpu: + alloc r2=ar.pfs,0,0,0,0 + stf.spill [sp]=f0 + mov f32=f0 + ;; + ldf.fill f33=[sp] + ldf.fill f34=[sp] + mov f35=f0 + ;; + ldf.fill f36=[sp] + ldf.fill f37=[sp] + mov f38=f0 + ;; + ldf.fill f39=[sp] + ldf.fill f40=[sp] + mov f41=f0 + ;; + ldf.fill f42=[sp] + ldf.fill f43=[sp] + mov f44=f0 + ;; + ldf.fill f45=[sp] + ldf.fill f46=[sp] + mov f47=f0 + ;; + ldf.fill f48=[sp] + ldf.fill f49=[sp] + mov f50=f0 + ;; + ldf.fill f51=[sp] + ldf.fill f52=[sp] + mov f53=f0 + ;; + ldf.fill f54=[sp] + ldf.fill f55=[sp] + mov f56=f0 + ;; + ldf.fill f57=[sp] + ldf.fill f58=[sp] + mov f59=f0 + ;; + ldf.fill f60=[sp] + ldf.fill f61=[sp] + mov f62=f0 + ;; + ldf.fill f63=[sp] + ldf.fill f64=[sp] + mov f65=f0 + ;; + ldf.fill f66=[sp] + ldf.fill f67=[sp] + mov f68=f0 + ;; + ldf.fill f69=[sp] + ldf.fill f70=[sp] + mov f71=f0 + ;; + ldf.fill f72=[sp] + ldf.fill f73=[sp] + mov f74=f0 + ;; + ldf.fill f75=[sp] + ldf.fill f76=[sp] + mov f77=f0 + ;; + ldf.fill f78=[sp] + ldf.fill f79=[sp] + mov f80=f0 + ;; + ldf.fill f81=[sp] + ldf.fill f82=[sp] + mov f83=f0 + ;; + ldf.fill f84=[sp] + ldf.fill f85=[sp] + mov f86=f0 + ;; + ldf.fill f87=[sp] + ldf.fill f88=[sp] + mov f89=f0 + ;; + ldf.fill f90=[sp] + ldf.fill f91=[sp] + mov f92=f0 + ;; + ldf.fill f93=[sp] + ldf.fill f94=[sp] + mov f95=f0 + ;; + ldf.fill f96=[sp] + ldf.fill f97=[sp] + mov f98=f0 + ;; + ldf.fill f99=[sp] + ldf.fill f100=[sp] + mov f101=f0 + ;; + ldf.fill f102=[sp] + ldf.fill f103=[sp] + mov f104=f0 + ;; + ldf.fill f105=[sp] + ldf.fill f106=[sp] + mov f107=f0 + ;; + ldf.fill f108=[sp] + ldf.fill f109=[sp] + mov f110=f0 + ;; + ldf.fill f111=[sp] + ldf.fill f112=[sp] + mov f113=f0 + ;; + ldf.fill f114=[sp] + ldf.fill f115=[sp] + mov f116=f0 + ;; + ldf.fill f117=[sp] + ldf.fill f118=[sp] + mov f119=f0 + ;; + ldf.fill f120=[sp] + ldf.fill f121=[sp] + mov f122=f0 + ;; + ldf.fill f123=[sp] + ldf.fill f124=[sp] + mov f125=f0 + ;; + ldf.fill f126=[sp] + mov f127=f0 + br.ret.sptk.few rp + .endp __ia64_init_fpu diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/init_task.c linux/arch/ia64/kernel/init_task.c --- v2.3.42/linux/arch/ia64/kernel/init_task.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/init_task.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,31 @@ +/* + * This is where we statically allocate and initialize the initial + * task. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + */ + +#include +#include +#include + +#include +#include + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM(init_mm); + +/* + * Initial task structure. + * + * We need to make sure that this is page aligned due to the way + * process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union task_union init_task_union + __attribute__((section("init_task"))) = + { INIT_TASK(init_task_union.task) }; diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.3.42/linux/arch/ia64/kernel/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/irq.c Wed Feb 9 19:45:43 2000 @@ -0,0 +1,657 @@ +/* + * linux/arch/ia64/kernel/irq.c + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998, 1999 Stephane Eranian + * Copyright (C) 1999-2000 David Mosberger-Tang + * + * 6/10/99: Updated to bring in sync with x86 version to facilitate + * support for SMP and different interrupt controllers. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for rand_initialize_irq() */ +#include +#include +#include +#include + +#ifdef CONFIG_KDB +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +/* This is used to detect bad usage of probe_irq_on()/probe_irq_off(). */ +#define PROBE_IRQ_COOKIE 0xfeedC0FFEE + +struct irq_desc irq_desc[NR_IRQS]; + +/* + * Micro-access to controllers is serialized over the whole + * system. We never hold this lock when we call the actual + * IRQ handler. + */ +spinlock_t irq_controller_lock; + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +spinlock_t ivr_read_lock; +#endif + +unsigned int local_bh_count[NR_CPUS]; +/* + * used in irq_enter()/irq_exit() + */ +unsigned int local_irq_count[NR_CPUS]; + +static struct irqaction timer_action = { NULL, 0, 0, NULL, NULL, NULL}; + +#ifdef CONFIG_SMP +static struct irqaction ipi_action = { NULL, 0, 0, NULL, NULL, NULL}; +#endif + +/* + * Legacy IRQ to IA-64 vector translation table. Any vector not in + * this table maps to itself (ie: irq 0x30 => IA64 vector 0x30) + */ +__u8 irq_to_vector_map[IA64_MIN_VECTORED_IRQ] = { + /* 8259 IRQ translation, first 16 entries */ + TIMER_IRQ, 0x50, 0x0f, 0x51, 0x52, 0x53, 0x43, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x40, 0x41, +}; + +/* + * Reverse of the above table. + */ +static __u8 vector_to_legacy_map[256]; + +/* + * used by proc fs (/proc/interrupts) + */ +int +get_irq_list (char *buf) +{ + int i; + struct irqaction * action; + char *p = buf; + +#ifdef CONFIG_SMP + p += sprintf(p, " "); + for (i = 0; i < smp_num_cpus; i++) + p += sprintf(p, "CPU%d ", i); + *p++ = '\n'; +#endif + /* + * Simply scans the external vectored interrupts + */ + for (i = 0; i < NR_IRQS; i++) { + action = irq_desc[i].action; + if (!action) + continue; + p += sprintf(p, "%3d: ",i); +#ifndef CONFIG_SMP + p += sprintf(p, "%10u ", kstat_irqs(i)); +#else + { + int j; + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + kstat.irqs[cpu_logical_map(j)][i]); + } +#endif + p += sprintf(p, " %14s", irq_desc[i].handler->typename); + p += sprintf(p, " %c%s", (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + + for (action = action->next; action; action = action->next) { + p += sprintf(p, ", %c%s", + (action->flags & SA_INTERRUPT)?'+':' ', + action->name); + } + *p++ = '\n'; + } + return p - buf; +} + +/* + * That's where the IVT branches when we get an external + * interrupt. This branches to the correct hardware IRQ handler via + * function ptr. + */ +void +ia64_handle_irq (unsigned long irq, struct pt_regs *regs) +{ + unsigned long bsp, sp, saved_tpr; + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +# ifndef CONFIG_SMP + static unsigned int max_prio = 0; +# endif + unsigned int prev_prio; + unsigned long eoi_ptr; + +# ifdef CONFIG_USB + disable_usb(); +# endif + /* + * Stop IPIs by getting the ivr_read_lock + */ + spin_lock(&ivr_read_lock); + + /* + * Disable PCI writes + */ + outl(0x80ff81c0, 0xcf8); + outl(0x73002188, 0xcfc); + eoi_ptr = inl(0xcfc); + + irq = ia64_get_ivr(); + + /* + * Enable PCI writes + */ + outl(0x73182188, 0xcfc); + + spin_unlock(&ivr_read_lock); + +# ifdef CONFIG_USB + reenable_usb(); +# endif + +# ifndef CONFIG_SMP + prev_prio = max_prio; + if (irq < max_prio) { + printk ("ia64_handle_irq: got irq %lu while %u was in progress!\n", + irq, max_prio); + + } else + max_prio = irq; +# endif /* !CONFIG_SMP */ +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ + + /* Always set TPR to limit maximum interrupt nesting depth to + * 16 (without this, it would be ~240, which could easily lead + * to kernel stack overflows. + */ + saved_tpr = ia64_get_tpr(); + ia64_srlz_d(); + ia64_set_tpr(irq); + ia64_srlz_d(); + + asm ("mov %0=ar.bsp" : "=r"(bsp)); + asm ("mov %0=sp" : "=r"(sp)); + + if ((sp - bsp) < 1024) { + static long last_time; + static unsigned char count; + + if (count > 5 && jiffies - last_time > 5*HZ) + count = 0; + if (++count < 5) { + last_time = jiffies; + printk("ia64_handle_irq: DANGER: less than 1KB of free stack space!!\n" + "(bsp=0x%lx, sp=%lx)\n", bsp, sp); + } +#ifdef CONFIG_KDB + kdb(KDB_REASON_PANIC, 0, regs); +#endif + } + + /* + * The interrupt is now said to be in service + */ + if (irq >= NR_IRQS) { + printk("handle_irq: invalid irq=%lu\n", irq); + goto out; + } + + ++kstat.irqs[smp_processor_id()][irq]; + + if (irq == IA64_SPURIOUS_INT) { + printk("handle_irq: spurious interrupt\n"); + goto out; + } + + /* + * Handle the interrupt by calling the hardware specific handler (IOSAPIC, Internal, etc). + */ + (*irq_desc[irq].handler->handle)(irq, regs); + out: +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + { + long pEOI; + + asm ("mov %0=0;; (p1) mov %0=1" : "=r"(pEOI)); + if (!pEOI) { + printk("Yikes: ia64_handle_irq() without pEOI!!\n"); + asm volatile ("cmp.eq p1,p0=r0,r0" : "=r"(pEOI)); +# ifdef CONFIG_KDB + kdb(KDB_REASON_PANIC, 0, regs); +# endif + } + } + + local_irq_disable(); +# ifndef CONFIG_SMP + if (max_prio == irq) + max_prio = prev_prio; +# endif /* !CONFIG_SMP */ +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ + + ia64_srlz_d(); + ia64_set_tpr(saved_tpr); + ia64_srlz_d(); +} + + +/* + * This should really return information about whether we should do + * bottom half handling etc. Right now we end up _always_ checking the + * bottom half, which is a waste of time and is not what some drivers + * would prefer. + */ +int +invoke_irq_handlers (unsigned int irq, struct pt_regs *regs, struct irqaction *action) +{ + void (*handler)(int, void *, struct pt_regs *); + unsigned long flags, flags_union = 0; + int cpu = smp_processor_id(); + unsigned int requested_irq; + void *dev_id; + + irq_enter(cpu, irq); + + if ((action->flags & SA_INTERRUPT) == 0) + __sti(); + + do { + flags = action->flags; + requested_irq = irq; + if ((flags & SA_LEGACY) != 0) + requested_irq = vector_to_legacy_map[irq]; + flags_union |= flags; + handler = action->handler; + dev_id = action->dev_id; + action = action->next; + (*handler)(requested_irq, dev_id, regs); + } while (action); + if ((flags_union & SA_SAMPLE_RANDOM) != 0) + add_interrupt_randomness(irq); + __cli(); + + irq_exit(cpu, irq); + return flags_union | 1; /* force the "do bottom halves" bit */ +} + +void +disable_irq_nosync (unsigned int irq) +{ + unsigned long flags; + + irq = map_legacy_irq(irq); + + spin_lock_irqsave(&irq_controller_lock, flags); + if (irq_desc[irq].depth++ > 0) { + irq_desc[irq].status &= ~IRQ_ENABLED; + irq_desc[irq].handler->disable(irq); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +/* + * Synchronous version of the above, making sure the IRQ is + * no longer running on any other IRQ.. + */ +void +disable_irq (unsigned int irq) +{ + disable_irq_nosync(irq); + + irq = map_legacy_irq(irq); + + if (!local_irq_count[smp_processor_id()]) { + do { + barrier(); + } while ((irq_desc[irq].status & IRQ_INPROGRESS) != 0); + } +} + +void +enable_irq (unsigned int irq) +{ + unsigned long flags; + + irq = map_legacy_irq(irq); + + spin_lock_irqsave(&irq_controller_lock, flags); + switch (irq_desc[irq].depth) { + case 1: + irq_desc[irq].status |= IRQ_ENABLED; + (*irq_desc[irq].handler->enable)(irq); + /* fall through */ + default: + --irq_desc[irq].depth; + break; + + case 0: + printk("enable_irq: unbalanced from %p\n", __builtin_return_address(0)); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +/* + * This function encapsulates the initialization that needs to be + * performed under the protection of lock irq_controller_lock. The + * lock must have been acquired by the time this is called. + */ +static inline int +setup_irq (unsigned int irq, struct irqaction *new) +{ + int shared = 0; + struct irqaction *old, **p; + + p = &irq_desc[irq].action; + old = *p; + if (old) { + if (!(old->flags & new->flags & SA_SHIRQ)) { + return -EBUSY; + } + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + *p = new; + + /* when sharing do not unmask */ + if (!shared) { + irq_desc[irq].depth = 0; + irq_desc[irq].status |= IRQ_ENABLED; + (*irq_desc[irq].handler->startup)(irq); + } + return 0; +} + +int +request_irq (unsigned int requested_irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + int retval, need_kfree = 0; + struct irqaction *action; + unsigned long flags; + unsigned int irq; + +#ifdef IA64_DEBUG + printk("request_irq(0x%x) called\n", requested_irq); +#endif + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if ((irqflags & SA_SHIRQ) && !dev_id) + printk("Bad boy: %s (at %p) called us without a dev_id!\n", + devname, current_text_addr()); + + irq = map_legacy_irq(requested_irq); + if (irq != requested_irq) + irqflags |= SA_LEGACY; + + if (irq >= NR_IRQS) + return -EINVAL; + + if (!handler) + return -EINVAL; + + /* + * The timer_action and ipi_action cannot be allocated + * dynamically because its initialization happens really early + * on in init/main.c at this point the memory allocator has + * not yet been initialized. So we use a statically reserved + * buffer for it. In some sense that's no big deal because we + * need one no matter what. + */ + if (irq == TIMER_IRQ) + action = &timer_action; +#ifdef CONFIG_SMP + else if (irq == IPI_IRQ) + action = &ipi_action; +#endif + else { + action = kmalloc(sizeof(struct irqaction), GFP_KERNEL); + need_kfree = 1; + } + + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + if ((irqflags & SA_SAMPLE_RANDOM) != 0) + rand_initialize_irq(irq); + + spin_lock_irqsave(&irq_controller_lock, flags); + retval = setup_irq(irq, action); + spin_unlock_irqrestore(&irq_controller_lock, flags); + + if (need_kfree && retval) + kfree(action); + + return retval; +} + +void +free_irq (unsigned int irq, void *dev_id) +{ + struct irqaction *action, **p; + unsigned long flags; + + /* + * some sanity checks first + */ + if (irq >= NR_IRQS) { + printk("Trying to free IRQ%d\n",irq); + return; + } + + irq = map_legacy_irq(irq); + + /* + * Find the corresponding irqaction + */ + spin_lock_irqsave(&irq_controller_lock, flags); + for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *p = action->next; + if (!irq_desc[irq].action) { + irq_desc[irq].status &= ~IRQ_ENABLED; + (*irq_desc[irq].handler->shutdown)(irq); + } + + spin_unlock_irqrestore(&irq_controller_lock, flags); + +#ifdef CONFIG_SMP + /* Wait to make sure it's not being used on another CPU */ + while (irq_desc[irq].status & IRQ_INPROGRESS) + barrier(); +#endif + + if (action != &timer_action +#ifdef CONFIG_SMP + && action != &ipi_action +#endif + ) + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n", irq); +} + +/* + * IRQ autodetection code. Note that the return value of + * probe_irq_on() is no longer being used (it's role has been replaced + * by the IRQ_AUTODETECT flag). + */ +unsigned long +probe_irq_on (void) +{ + struct irq_desc *id; + unsigned long delay; + +#ifdef IA64_DEBUG + printk("probe_irq_on() called\n"); +#endif + + spin_lock_irq(&irq_controller_lock); + for (id = irq_desc; id < irq_desc + NR_IRQS; ++id) { + if (!id->action) { + id->status |= IRQ_AUTODETECT | IRQ_WAITING; + (*id->handler->startup)(id - irq_desc); + } + } + spin_unlock_irq(&irq_controller_lock); + + /* wait for spurious interrupts to trigger: */ + + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ + synchronize_irq(); + + /* filter out obviously spurious interrupts: */ + spin_lock_irq(&irq_controller_lock); + for (id = irq_desc; id < irq_desc + NR_IRQS; ++id) { + unsigned int status = id->status; + + if (!(status & IRQ_AUTODETECT)) + continue; + + if (!(status & IRQ_WAITING)) { + id->status = status & ~IRQ_AUTODETECT; + (*id->handler->shutdown)(id - irq_desc); + } + } + spin_unlock_irq(&irq_controller_lock); + return PROBE_IRQ_COOKIE; /* return meaningless return value */ +} + +int +probe_irq_off (unsigned long cookie) +{ + int irq_found, nr_irqs; + struct irq_desc *id; + +#ifdef IA64_DEBUG + printk("probe_irq_off(cookie=0x%lx) -> ", cookie); +#endif + + if (cookie != PROBE_IRQ_COOKIE) + printk("bad irq probe from %p\n", __builtin_return_address(0)); + + nr_irqs = 0; + irq_found = 0; + spin_lock_irq(&irq_controller_lock); + for (id = irq_desc + IA64_MIN_VECTORED_IRQ; id < irq_desc + NR_IRQS; ++id) { + unsigned int status = id->status; + + if (!(status & IRQ_AUTODETECT)) + continue; + + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = (id - irq_desc); + ++nr_irqs; + } + id->status = status & ~IRQ_AUTODETECT; + (*id->handler->shutdown)(id - irq_desc); + } + spin_unlock_irq(&irq_controller_lock); + + if (nr_irqs > 1) + irq_found = -irq_found; + +#ifdef IA64_DEBUG + printk("%d\n", irq_found); +#endif + return irq_found; +} + +#ifdef CONFIG_SMP + +void __init +init_IRQ_SMP (void) +{ + if (request_irq(IPI_IRQ, handle_IPI, 0, "IPI", NULL)) + panic("Could not allocate IPI Interrupt Handler!"); +} + +#endif + +void __init +init_IRQ (void) +{ + int i; + + for (i = 0; i < IA64_MIN_VECTORED_IRQ; ++i) + vector_to_legacy_map[irq_to_vector_map[i]] = i; + + for (i = 0; i < NR_IRQS; ++i) { + irq_desc[i].handler = &irq_type_default; + } + + irq_desc[TIMER_IRQ].handler = &irq_type_ia64_internal; +#ifdef CONFIG_SMP + /* + * Configure the IPI vector and handler + */ + irq_desc[IPI_IRQ].handler = &irq_type_ia64_internal; + init_IRQ_SMP(); +#endif + + ia64_set_pmv(1 << 16); + ia64_set_cmcv(CMC_IRQ); /* XXX fix me */ + + platform_irq_init(irq_desc); + + /* clear TPR to enable all interrupt classes: */ + ia64_set_tpr(0); +} + +/* TBD: + * Certain IA64 platforms can have inter-processor interrupt support. + * This interface is supposed to default to the IA64 IPI block-based + * mechanism if the platform doesn't provide a separate mechanism + * for IPIs. + * Choices : (1) Extend hw_interrupt_type interfaces + * (2) Use machine vector mechanism + * For now defining the following interface as a place holder. + */ +void +ipi_send (int cpu, int vector, int delivery_mode) +{ +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/irq_default.c linux/arch/ia64/kernel/irq_default.c --- v2.3.42/linux/arch/ia64/kernel/irq_default.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/irq_default.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,30 @@ +#include +#include + +#include +#include +#include + + +static int +irq_default_handle_irq (unsigned int irq, struct pt_regs *regs) +{ + printk("Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id()); + return 0; /* don't call do_bottom_half() for spurious interrupts */ +} + +static void +irq_default_noop (unsigned int irq) +{ + /* nuthing to do... */ +} + +struct hw_interrupt_type irq_type_default = { + "default", + (void (*)(unsigned long)) irq_default_noop, /* init */ + irq_default_noop, /* startup */ + irq_default_noop, /* shutdown */ + irq_default_handle_irq, /* handle */ + irq_default_noop, /* enable */ + irq_default_noop /* disable */ +}; diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/irq_internal.c linux/arch/ia64/kernel/irq_internal.c --- v2.3.42/linux/arch/ia64/kernel/irq_internal.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/irq_internal.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,71 @@ +/* + * Internal Interrupt Vectors + * + * This takes care of interrupts that are generated by the CPU + * internally, such as the ITC and IPI interrupts. + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + */ + +#include +#include + +#include +#include +#include + +/* + * This is identical to IOSAPIC handle_irq. It may go away . . . + */ +static int +internal_handle_irq (unsigned int irq, struct pt_regs *regs) +{ + struct irqaction *action = 0; + struct irq_desc *id = irq_desc + irq; + unsigned int status; + int retval; + + spin_lock(&irq_controller_lock); + { + status = id->status; + if ((status & IRQ_ENABLED) != 0) + action = id->action; + id->status = status & ~(IRQ_REPLAY | IRQ_WAITING); + } + spin_unlock(&irq_controller_lock); + + if (!action) { + if (!(id->status & IRQ_AUTODETECT)) + printk("irq_hpsim_handle_irq: unexpected interrupt %u\n", irq); + return 0; + } + + retval = invoke_irq_handlers(irq, regs, action); + + spin_lock(&irq_controller_lock); + { + status = (id->status & ~IRQ_INPROGRESS); + id->status = status; + } + spin_unlock(&irq_controller_lock); + + return retval; +} + +static void +internal_noop (unsigned int irq) +{ + /* nuthing to do... */ +} + +struct hw_interrupt_type irq_type_ia64_internal = { + "IA64 internal", + (void (*)(unsigned long)) internal_noop, /* init */ + internal_noop, /* startup */ + internal_noop, /* shutdown */ + internal_handle_irq, /* handle */ + internal_noop, /* enable */ + internal_noop /* disable */ +}; + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/irq_lock.c linux/arch/ia64/kernel/irq_lock.c --- v2.3.42/linux/arch/ia64/kernel/irq_lock.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/irq_lock.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,287 @@ +/* + * SMP IRQ Lock support + * + * Global interrupt locks for SMP. Allow interrupts to come in on any + * CPU, yet make cli/sti act globally to protect critical regions.. + * These function usually appear in irq.c, but I think it's cleaner this way. + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int global_irq_holder = NO_PROC_ID; +spinlock_t global_irq_lock; +atomic_t global_irq_count; +atomic_t global_bh_count; +atomic_t global_bh_lock; + +#define INIT_STUCK (1<<26) + +void +irq_enter(int cpu, int irq) +{ + int stuck = INIT_STUCK; + + hardirq_enter(cpu, irq); + barrier(); + while (global_irq_lock.lock) { + if (cpu == global_irq_holder) { + break; + } + + if (!--stuck) { + printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n", + irq, cpu,global_irq_holder); + stuck = INIT_STUCK; + } + barrier(); + } +} + +void +irq_exit(int cpu, int irq) +{ + hardirq_exit(cpu, irq); + release_irqlock(cpu); +} + +static void +show(char * str) +{ + int i; + unsigned long *stack; + int cpu = smp_processor_id(); + + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [%d %d]\n", + atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); + printk("bh: %d [%d %d]\n", + atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]); + + stack = (unsigned long *) &stack; + for (i = 40; i ; i--) { + unsigned long x = *++stack; + if (x > (unsigned long) &get_options && x < (unsigned long) &vsprintf) { + printk("<[%08lx]> ", x); + } + } +} + +#define MAXCOUNT 100000000 + +static inline void +wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if (!--count) { + show("wait_on_bh"); + count = ~0; + } + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} + +static inline void +wait_on_irq(int cpu) +{ + int count = MAXCOUNT; + + for (;;) { + + /* + * Wait until all interrupts are gone. Wait + * for bottom half handlers unless we're + * already executing in one.. + */ + if (!atomic_read(&global_irq_count)) { + if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + spin_unlock(&global_irq_lock); + mb(); + + for (;;) { + if (!--count) { + show("wait_on_irq"); + count = ~0; + } + __sti(); + udelay(cpu + 1); + __cli(); + if (atomic_read(&global_irq_count)) + continue; + if (global_irq_lock.lock) + continue; + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + continue; + if (spin_trylock(&global_irq_lock)) + break; + } + } +} + +/* + * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void +synchronize_bh(void) +{ + if (atomic_read(&global_bh_count)) { + int cpu = smp_processor_id(); + if (!local_irq_count[cpu] && !local_bh_count[cpu]) { + wait_on_bh(); + } + } +} + + +/* + * This is called when we want to synchronize with + * interrupts. We may for example tell a device to + * stop sending interrupts: but to make sure there + * are no interrupts that are executing on another + * CPU we need to call this function. + */ +void +synchronize_irq(void) +{ + int cpu = smp_processor_id(); + int local_count; + int global_count; + + mb(); + do { + local_count = local_irq_count[cpu]; + global_count = atomic_read(&global_irq_count); + } while (global_count != local_count); +} + +static inline void +get_irqlock(int cpu) +{ + if (!spin_trylock(&global_irq_lock)) { + /* do we already hold the lock? */ + if ((unsigned char) cpu == global_irq_holder) + return; + /* Uhhuh.. Somebody else got it. Wait.. */ + spin_lock(&global_irq_lock); + } + /* + * We also to make sure that nobody else is running + * in an interrupt context. + */ + wait_on_irq(cpu); + + /* + * Ok, finally.. + */ + global_irq_holder = cpu; +} + +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + * + * If we already have local interrupts disabled, + * this will not turn a local disable into a + * global one (problems with spinlocks: this makes + * save_flags+cli+sti usable inside a spinlock). + */ +void +__global_cli(void) +{ + unsigned long flags; + + __save_flags(flags); + if (flags & IA64_PSR_I) { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count[cpu]) + get_irqlock(cpu); + } +} + +void +__global_sti(void) +{ + int cpu = smp_processor_id(); + + if (!local_irq_count[cpu]) + release_irqlock(cpu); + __sti(); +} + +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ +unsigned long +__global_save_flags(void) +{ + int retval; + int local_enabled; + unsigned long flags; + + __save_flags(flags); + local_enabled = flags & IA64_PSR_I; + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count[smp_processor_id()]) { + if (local_enabled) + retval = 1; + if (global_irq_holder == (unsigned char) smp_processor_id()) + retval = 0; + } + return retval; +} + +void +__global_restore_flags(unsigned long flags) +{ + switch (flags) { + case 0: + __global_cli(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + printk("global_restore_flags: %08lx (%08lx)\n", + flags, (&flags)[-1]); + } +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S --- v2.3.42/linux/arch/ia64/kernel/ivt.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/ivt.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,1342 @@ +/* + * arch/ia64/kernel/ivt.S + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998, 1999 Stephane Eranian + * Copyright (C) 1998-2000 David Mosberger + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "entry.h" + +/* + * A couple of convenience macros that make writing and reading + * SAVE_MIN and SAVE_REST easier. + */ +#define rARPR r31 +#define rCRIFS r30 +#define rCRIPSR r29 +#define rCRIIP r28 +#define rARRSC r27 +#define rARPFS r26 +#define rARUNAT r25 +#define rARRNAT r24 +#define rARBSPSTORE r23 +#define rKRBS r22 +#define rB6 r21 +#define rR1 r20 + +/* + * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves + * the minimum state necessary that allows us to turn psr.ic back + * on. + * + * Assumed state upon entry: + * psr.ic: off + * psr.dt: off + * r31: contains saved predicates (pr) + * + * Upon exit, the state is as follows: + * psr.ic: off + * psr.dt: off + * r2 = points to &pt_regs.r16 + * r12 = kernel sp (kernel virtual address) + * r13 = points to current task_struct (kernel virtual address) + * p15 = TRUE if psr.i is set in cr.ipsr + * predicate registers (other than p6, p7, and p15), b6, r3, r8, r9, r10, r11, r14, r15: + * preserved + * + * Note that psr.ic is NOT turned on by this macro. This is so that + * we can pass interruption state as arguments to a handler. + */ +#define DO_SAVE_MIN(COVER,EXTRA) \ + mov rARRSC=ar.rsc; \ + mov rARPFS=ar.pfs; \ + mov rR1=r1; \ + mov rARUNAT=ar.unat; \ + mov rCRIPSR=cr.ipsr; \ + mov rB6=b6; /* rB6 = branch reg 6 */ \ + mov rCRIIP=cr.iip; \ + mov r1=ar.k6; /* r1 = current */ \ + ;; \ + invala; \ + extr.u r16=rCRIPSR,32,2; /* extract psr.cpl */ \ + ;; \ + cmp.eq pKern,p7=r0,r16; /* are we in kernel mode already? (psr.cpl==0) */ \ + /* switch from user to kernel RBS: */ \ + COVER; \ + ;; \ +(p7) mov ar.rsc=r0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ +(p7) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ + ;; \ +(p7) mov rARRNAT=ar.rnat; \ +(pKern) dep r1=0,sp,61,3; /* compute physical addr of sp */ \ +(p7) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ +(p7) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ +(p7) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */ \ + ;; \ +(pKern) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ +(p7) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ + ;; \ +(p7) mov r18=ar.bsp; \ +(p7) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ + \ + mov r16=r1; /* initialize first base pointer */ \ + adds r17=8,r1; /* initialize second base pointer */ \ + ;; \ + st8 [r16]=rCRIPSR,16; /* save cr.ipsr */ \ + st8 [r17]=rCRIIP,16; /* save cr.iip */ \ +(pKern) mov r18=r0; /* make sure r18 isn't NaT */ \ + ;; \ + st8 [r16]=rCRIFS,16; /* save cr.ifs */ \ + st8 [r17]=rARUNAT,16; /* save ar.unat */ \ +(p7) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ + ;; \ + st8 [r16]=rARPFS,16; /* save ar.pfs */ \ + st8 [r17]=rARRSC,16; /* save ar.rsc */ \ + tbit.nz p15,p0=rCRIPSR,IA64_PSR_I_BIT \ + ;; /* avoid RAW on r16 & r17 */ \ +(pKern) adds r16=16,r16; /* skip over ar_rnat field */ \ +(pKern) adds r17=16,r17; /* skip over ar_bspstore field */ \ +(p7) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ +(p7) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ + ;; \ + st8 [r16]=rARPR,16; /* save predicates */ \ + st8 [r17]=rB6,16; /* save b6 */ \ + shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ + ;; \ + st8 [r16]=r18,16; /* save ar.rsc value for "loadrs" */ \ + st8.spill [r17]=rR1,16; /* save original r1 */ \ + cmp.ne pEOI,p0=r0,r0 /* clear pEOI by default */ \ + ;; \ + st8.spill [r16]=r2,16; \ + st8.spill [r17]=r3,16; \ + adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ + ;; \ + st8.spill [r16]=r12,16; \ + st8.spill [r17]=r13,16; \ + cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ + ;; \ + st8.spill [r16]=r14,16; \ + st8.spill [r17]=r15,16; \ + dep r14=-1,r0,61,3; \ + ;; \ + st8.spill [r16]=r8,16; \ + st8.spill [r17]=r9,16; \ + adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ + ;; \ + st8.spill [r16]=r10,16; \ + st8.spill [r17]=r11,16; \ + mov r13=ar.k6; /* establish `current' */ \ + ;; \ + or r2=r2,r14; /* make first base a kernel virtual address */ \ + EXTRA; \ + movl r1=__gp; /* establish kernel global pointer */ \ + ;; \ + or r12=r12,r14; /* make sp a kernel virtual address */ \ + or r13=r13,r14; /* make `current' a kernel virtual address */ \ + bsw.1;; /* switch back to bank 1 (must be last in insn group) */ + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +# define STOPS nop.i 0x0;; nop.i 0x0;; nop.i 0x0;; +#else +# define STOPS +#endif + +#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs,) STOPS +#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover;; mov rCRIFS=cr.ifs, mov r15=r19) STOPS +#define SAVE_MIN DO_SAVE_MIN(mov rCRIFS=r0,) STOPS + +/* + * SAVE_REST saves the remainder of pt_regs (with psr.ic on). This + * macro guarantees to preserve all predicate registers, r8, r9, r10, + * r11, r14, and r15. + * + * Assumed state upon entry: + * psr.ic: on + * psr.dt: on + * r2: points to &pt_regs.r16 + * r3: points to &pt_regs.r17 + */ +#define SAVE_REST \ + st8.spill [r2]=r16,16; \ + st8.spill [r3]=r17,16; \ + ;; \ + st8.spill [r2]=r18,16; \ + st8.spill [r3]=r19,16; \ + ;; \ + mov r16=ar.ccv; /* M-unit */ \ + movl r18=FPSR_DEFAULT /* L-unit */ \ + ;; \ + mov r17=ar.fpsr; /* M-unit */ \ + mov ar.fpsr=r18; /* M-unit */ \ + ;; \ + st8.spill [r2]=r20,16; \ + st8.spill [r3]=r21,16; \ + mov r18=b0; \ + ;; \ + st8.spill [r2]=r22,16; \ + st8.spill [r3]=r23,16; \ + mov r19=b7; \ + ;; \ + st8.spill [r2]=r24,16; \ + st8.spill [r3]=r25,16; \ + ;; \ + st8.spill [r2]=r26,16; \ + st8.spill [r3]=r27,16; \ + ;; \ + st8.spill [r2]=r28,16; \ + st8.spill [r3]=r29,16; \ + ;; \ + st8.spill [r2]=r30,16; \ + st8.spill [r3]=r31,16; \ + ;; \ + st8 [r2]=r16,16; /* ar.ccv */ \ + st8 [r3]=r17,16; /* ar.fpsr */ \ + ;; \ + st8 [r2]=r18,16; /* b0 */ \ + st8 [r3]=r19,16+8; /* b7 */ \ + ;; \ + stf.spill [r2]=f6,32; \ + stf.spill [r3]=f7,32; \ + ;; \ + stf.spill [r2]=f8,32; \ + stf.spill [r3]=f9,32 + +/* + * This file defines the interrupt vector table used by the CPU. + * It does not include one entry per possible cause of interruption. + * + * External interrupts only use 1 entry. All others are internal interrupts + * + * The first 20 entries of the table contain 64 bundles each while the + * remaining 48 entries contain only 16 bundles each. + * + * The 64 bundles are used to allow inlining the whole handler for critical + * interrupts like TLB misses. + * + * For each entry, the comment is as follows: + * + * // 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) + * entry offset ----/ / / / / + * entry number ---------/ / / / + * size of the entry -------------/ / / + * vector name -------------------------------------/ / + * related interrupts (what is the real interrupt?) ----------/ + * + * The table is 32KB in size and must be aligned on 32KB boundary. + * (The CPU ignores the 15 lower bits of the address) + * + * Table is based upon EAS2.4 (June 1998) + */ + +#define FAULT(n) \ + rsm psr.dt; /* avoid nested faults due to TLB misses... */ \ + ;; \ + srlz.d; /* ensure everyone knows psr.dt is off... */ \ + mov r31=pr; \ + mov r19=n;; /* prepare to save predicates */ \ + br.cond.sptk.many dispatch_to_fault_handler + +/* + * As we don't (hopefully) use the space available, we need to fill it with + * nops. the parameter may be used for debugging and is representing the entry + * number + */ +#define BREAK_BUNDLE(a) break.m (a); \ + break.i (a); \ + break.i (a) +/* + * 4 breaks bundles all together + */ +#define BREAK_BUNDLE4(a); BREAK_BUNDLE(a); BREAK_BUNDLE(a); BREAK_BUNDLE(a); BREAK_BUNDLE(a) + +/* + * 8 bundles all together (too lazy to use only 4 at a time !) + */ +#define BREAK_BUNDLE8(a); BREAK_BUNDLE4(a); BREAK_BUNDLE4(a) + + .psr abi64 + .psr lsb + .lsb + + .section __ivt_section,"ax" + + .align 32768 // align on 32KB boundary + .global ia64_ivt +ia64_ivt: +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0000 Entry 0 (size 64 bundles) VHPT Translation (8,20,47) + /* + * The VHPT vector is invoked when the TLB entry for the virtual page table + * is missing. This happens only as a result of a previous + * (the "original") TLB miss, which may either be caused by an instruction + * fetch or a data access (or non-access). + * + * What we do here is normal TLB miss handing for the _original_ miss, followed + * by inserting the TLB entry for the virtual page table page that the VHPT + * walker was attempting to access. The latter gets inserted as long + * as both L1 and L2 have valid mappings for the faulting address. + * The TLB entry for the original miss gets inserted only if + * the L3 entry indicates that the page is present. + * + * do_page_fault gets invoked in the following cases: + * - the faulting virtual address uses unimplemented address bits + * - the faulting virtual address has no L1, L2, or L3 mapping + */ + mov r16=cr.ifa // get address that caused the TLB miss + ;; + rsm psr.dt // use physical addressing for data + mov r31=pr // save the predicate registers + mov r19=ar.k7 // get page table base address + shl r21=r16,3 // shift bit 60 into sign bit + shr.u r17=r16,61 // get the region number into r17 + ;; + cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? + shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of the faulting address + ;; +(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + srlz.d // ensure "rsm psr.dt" has taken effect +(p6) movl r19=__pa(SWAPPER_PGD_ADDR) // region 5 is rooted at swapper_pg_dir +(p6) shr r21=r21,PGDIR_SHIFT+PAGE_SHIFT-1 +(p7) shr r21=r21,PGDIR_SHIFT+PAGE_SHIFT-4 + ;; +(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 +(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) + cmp.eq p7,p6=0,r21 // unused address bits all zeroes? + shr.u r18=r16,PMD_SHIFT // shift L2 index into position + ;; +(p6) cmp.eq p7,p6=-1,r21 // unused address bits all ones? + ld8 r17=[r17] // fetch the L1 entry (may be 0) + ;; +(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? + dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry + ;; +(p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) + shr.u r19=r16,PAGE_SHIFT // shift L3 index into position + ;; +(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? + dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry + ;; +(p7) ld8 r18=[r17] // read the L3 PTE + mov r19=cr.isr // cr.isr bit 0 tells us if this is an insn miss + ;; +(p7) tbit.z p6,p7=r18,0 // page present bit cleared? + mov r21=cr.iha // get the VHPT address that caused the TLB miss + ;; // avoid RAW on p7 +(p7) tbit.nz.unc p10,p11=r19,32 // is it an instruction TLB miss? + dep r17=0,r17,0,PAGE_SHIFT // clear low bits to get page address + ;; +(p10) itc.i r18;; // insert the instruction TLB entry (EAS2.6: must be last in insn group!) +(p11) itc.d r18;; // insert the data TLB entry (EAS2.6: must be last in insn group!) +(p6) br.spnt.few page_fault // handle bad address/page not present (page fault) + mov cr.ifa=r21 + + // Now compute and insert the TLB entry for the virtual page table. + // We never execute in a page table page so there is no need to set + // the exception deferral bit. + adds r16=__DIRTY_BITS_NO_ED|_PAGE_PL_0|_PAGE_AR_RW,r17 + ;; +(p7) itc.d r16;; // EAS2.6: must be last in insn group! + mov pr=r31,-1 // restore predicate registers + rfi;; // must be last insn in an insn group + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0400 Entry 1 (size 64 bundles) ITLB (21) + /* + * The ITLB basically does the same as the VHPT handler except + * that we always insert exactly one instruction TLB entry. + */ + mov r16=cr.ifa // get address that caused the TLB miss + ;; + rsm psr.dt // use physical addressing for data + mov r31=pr // save the predicate registers + mov r19=ar.k7 // get page table base address + shl r21=r16,3 // shift bit 60 into sign bit + shr.u r17=r16,61 // get the region number into r17 + ;; + cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? + shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of the faulting address + ;; +(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + srlz.d // ensure "rsm psr.dt" has taken effect +(p6) movl r19=__pa(SWAPPER_PGD_ADDR) // region 5 is rooted at swapper_pg_dir +(p6) shr r21=r21,PGDIR_SHIFT+PAGE_SHIFT-1 +(p7) shr r21=r21,PGDIR_SHIFT+PAGE_SHIFT-4 + ;; +(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 +(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) + cmp.eq p7,p6=0,r21 // unused address bits all zeroes? + shr.u r18=r16,PMD_SHIFT // shift L2 index into position + ;; +(p6) cmp.eq p7,p6=-1,r21 // unused address bits all ones? + ld8 r17=[r17] // fetch the L1 entry (may be 0) + ;; +(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? + dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry + ;; +(p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) + shr.u r19=r16,PAGE_SHIFT // shift L3 index into position + ;; +(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? + dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry + ;; +(p7) ld8 r18=[r17] // read the L3 PTE + ;; +(p7) tbit.z p6,p7=r18,0 // page present bit cleared? + ;; +(p7) itc.i r18;; // insert the instruction TLB entry (EAS2.6: must be last in insn group!) +(p6) br.spnt.few page_fault // handle bad address/page not present (page fault) + ;; + mov pr=r31,-1 // restore predicate registers + rfi;; // must be last insn in an insn group + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0800 Entry 2 (size 64 bundles) DTLB (9,48) + /* + * The DTLB basically does the same as the VHPT handler except + * that we always insert exactly one data TLB entry. + */ + mov r16=cr.ifa // get address that caused the TLB miss + ;; + rsm psr.dt // use physical addressing for data + mov r31=pr // save the predicate registers + mov r19=ar.k7 // get page table base address + shl r21=r16,3 // shift bit 60 into sign bit + shr.u r17=r16,61 // get the region number into r17 + ;; + cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? + shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of the faulting address + ;; +(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + srlz.d // ensure "rsm psr.dt" has taken effect +(p6) movl r19=__pa(SWAPPER_PGD_ADDR) // region 5 is rooted at swapper_pg_dir +(p6) shr r21=r21,PGDIR_SHIFT+PAGE_SHIFT-1 +(p7) shr r21=r21,PGDIR_SHIFT+PAGE_SHIFT-4 + ;; +(p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 +(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) + cmp.eq p7,p6=0,r21 // unused address bits all zeroes? + shr.u r18=r16,PMD_SHIFT // shift L2 index into position + ;; +(p6) cmp.eq p7,p6=-1,r21 // unused address bits all ones? + ld8 r17=[r17] // fetch the L1 entry (may be 0) + ;; +(p7) cmp.eq p6,p7=r17,r0 // was L1 entry NULL? + dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry + ;; +(p7) ld8 r17=[r17] // fetch the L2 entry (may be 0) + shr.u r19=r16,PAGE_SHIFT // shift L3 index into position + ;; +(p7) cmp.eq.or.andcm p6,p7=r17,r0 // was L2 entry NULL? + dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry + ;; +(p7) ld8 r18=[r17] // read the L3 PTE + ;; +(p7) tbit.z p6,p7=r18,0 // page present bit cleared? + ;; +(p7) itc.d r18;; // insert the instruction TLB entry (EAS2.6: must be last in insn group!) +(p6) br.spnt.few page_fault // handle bad address/page not present (page fault) + ;; + mov pr=r31,-1 // restore predicate registers + rfi;; // must be last insn in an insn group + + //----------------------------------------------------------------------------------- + // call do_page_fault (predicates are in r31, psr.dt is off, r16 is faulting address) +page_fault: + SAVE_MIN_WITH_COVER + // + // Copy control registers to temporary registers, then turn on psr bits, + // then copy the temporary regs to the output regs. We have to do this + // because the "alloc" can cause a mandatory store which could lead to + // an "Alt DTLB" fault which we can handle only if psr.ic is on. + // + mov r8=cr.ifa + mov r9=cr.isr + adds r3=8,r2 // set up second base pointer + ;; + ssm psr.ic | psr.dt + ;; + srlz.d // guarantee that interrupt collection is enabled +(p15) ssm psr.i // restore psr.i + ;; + srlz.i // must precede "alloc"! (srlz.i implies srlz.d) + movl r14=ia64_leave_kernel + ;; + alloc r15=ar.pfs,0,0,3,0 // must be first in insn group + mov out0=r8 + mov out1=r9 + ;; + SAVE_REST + mov rp=r14 + ;; + adds out2=16,r12 // out2 = pointer to pt_regs + br.call.sptk.few b6=ia64_do_page_fault // ignore return address + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x0c00 Entry 3 (size 64 bundles) Alt ITLB (19) + mov r16=cr.ifa // get address that caused the TLB miss + movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RX + ;; + shr.u r18=r16,57 // move address bit 61 to bit 4 + dep r16=0,r16,52,12 // clear top 12 bits of address + ;; + andcm r18=0x10,r18 // bit 4=~address-bit(61) + dep r16=r17,r16,0,12 // insert PTE control bits into r16 + ;; + or r16=r16,r18 // set bit 4 (uncached) if the access was to region 6 + ;; + itc.i r16;; // insert the TLB entry(EAS2.6: must be last in insn group!) + rfi;; // must be last insn in an insn group + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1000 Entry 4 (size 64 bundles) Alt DTLB (7,46) + mov r16=cr.ifa // get address that caused the TLB miss + movl r17=__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW + ;; + shr.u r18=r16,57 // move address bit 61 to bit 4 + dep r16=0,r16,52,12 // clear top 12 bits of address + ;; + andcm r18=0x10,r18 // bit 4=~address-bit(61) + dep r16=r17,r16,0,12 // insert PTE control bits into r16 + ;; + or r16=r16,r18 // set bit 4 (uncached) if the access was to region 6 + ;; + itc.d r16;; // insert the TLB entry (EAS2.6: must be last in insn group!) + rfi;; // must be last insn in an insn group + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1400 Entry 5 (size 64 bundles) Data nested TLB (6,45) + // + // In the absence of kernel bugs, we get here when the Dirty-bit, Instruction + // Access-bit, or Data Access-bit faults cause a nested fault because the + // dTLB entry for the virtual page table isn't present. In such a case, + // we lookup the pte for the faulting address by walking the page table + // and return to the contination point passed in register r30. + // In accessing the page tables, we don't need to check for NULL entries + // because if the page tables didn't map the faulting address, it would not + // be possible to receive one of the above faults. + // + // Input: r16: faulting address + // r29: saved b0 + // r30: continuation address + // + // Output: r17: physical address of L3 PTE of faulting address + // r29: saved b0 + // r30: continuation address + // + // Clobbered: b0, r18, r19, r21, r31, psr.dt (cleared) + // + rsm psr.dt // switch to using physical data addressing + mov r19=ar.k7 // get the page table base address + shl r21=r16,3 // shift bit 60 into sign bit + ;; + mov r31=pr // save the predicate registers + shr.u r17=r16,61 // get the region number into r17 + ;; + cmp.eq p6,p7=5,r17 // is faulting address in region 5? + shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of faulting address + ;; +(p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + srlz.d +(p6) movl r17=__pa(SWAPPER_PGD_ADDR) // region 5 is rooted at swapper_pg_dir +(p6) shr r21=r21,PGDIR_SHIFT+PAGE_SHIFT-1 +(p7) shr r21=r21,PGDIR_SHIFT+PAGE_SHIFT-4 + ;; +(p6) dep r17=r18,r17,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 +(p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) + shr.u r18=r16,PMD_SHIFT // shift L2 index into position + ;; + ld8 r17=[r17] // fetch the L1 entry + mov b0=r30 + ;; + dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry + ;; + ld8 r17=[r17] // fetch the L2 entry + shr.u r19=r16,PAGE_SHIFT // shift L3 index into position + ;; + dep r17=r19,r17,3,(PAGE_SHIFT-3) // compute address of L3 page table entry + ;; + mov pr=r31,-1 // restore predicates + br.cond.sptk.few b0 // return to continuation point + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1800 Entry 6 (size 64 bundles) Instruction Key Miss (24) + FAULT(6) + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x1c00 Entry 7 (size 64 bundles) Data Key Miss (12,51) + FAULT(7) + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2000 Entry 8 (size 64 bundles) Dirty-bit (54) + // + // What we do here is to simply turn on the dirty bit in the PTE. We need + // to update both the page-table and the TLB entry. To efficiently access + // the PTE, we address it through the virtual page table. Most likely, the + // TLB entry for the relevant virtual page table page is still present in + // the TLB so we can normally do this without additional TLB misses. + // In case the necessary virtual page table TLB entry isn't present, we take + // a nested TLB miss hit where we look up the physical address of the L3 PTE + // and then continue at label 1 below. + // + mov r16=cr.ifa // get the address that caused the fault + movl r30=1f // load continuation point in case of nested fault + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r29=b0 // save b0 in case of nested fault + ;; +1: ld8 r18=[r17] + ;; // avoid RAW on r18 + or r18=_PAGE_D,r18 // set the dirty bit + mov b0=r29 // restore b0 + ;; + st8 [r17]=r18 // store back updated PTE + itc.d r18;; // install updated PTE (EAS2.6: must be last in insn group!) + rfi;; // must be last insn in an insn group + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) + // Like Entry 8, except for instruction access + mov r16=cr.ifa // get the address that caused the fault +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + mov r31=pr // save predicates + mov r30=cr.ipsr + ;; + extr.u r17=r30,IA64_PSR_IS_BIT,1 // get instruction arch. indicator + ;; + cmp.eq p6,p0 = r17,r0 // check if IA64 instruction set + ;; +(p6) mov r16=cr.iip // get real faulting address + ;; +(p6) mov cr.ifa=r16 // reset IFA + mov pr=r31,-1 +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ + movl r30=1f // load continuation point in case of nested fault + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r29=b0 // save b0 in case of nested fault) + ;; +1: ld8 r18=[r17] + ;; // avoid raw on r18 + or r18=_PAGE_A,r18 // set the accessed bit + mov b0=r29 // restore b0 + ;; + st8 [r17]=r18 // store back updated PTE + itc.i r18;; // install updated PTE (EAS2.6: must be last in insn group!) + rfi;; // must be last insn in an insn group + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) + // Like Entry 8, except for data access + mov r16=cr.ifa // get the address that caused the fault + movl r30=1f // load continuation point in case of nested fault + ;; + thash r17=r16 // compute virtual address of L3 PTE + mov r29=b0 // save b0 in case of nested fault) + ;; +1: ld8 r18=[r17] + ;; // avoid RAW on r18 + or r18=_PAGE_A,r18 // set the accessed bit + mov b0=r29 // restore b0 + ;; + st8 [r17]=r18 // store back updated PTE + itc.d r18;; // install updated PTE (EAS2.6: must be last in insn group!) + rfi;; // must be last insn in an insn group + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) + mov r16=cr.iim + mov r17=__IA64_BREAK_SYSCALL + mov r31=pr // prepare to save predicates + rsm psr.dt // avoid nested faults due to TLB misses... + ;; + srlz.d // ensure everyone knows psr.dt is off... + cmp.eq p0,p7=r16,r17 // is this a system call? (p7 <- false, if so) + +#if 1 + // Allow syscalls via the old system call number for the time being. This is + // so we can transition to the new syscall number in a relatively smooth + // fashion. + mov r17=0x80000 + ;; +(p7) cmp.eq.or.andcm p0,p7=r16,r17 // is this the old syscall number? +#endif + +(p7) br.cond.spnt.many non_syscall + + SAVE_MIN // uses r31; defines r2: + + // turn interrupt collection and data translation back on: + ssm psr.ic | psr.dt + srlz.d // guarantee that interrupt collection is enabled + cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + ;; +(p15) ssm psr.i // restore psr.i + ;; + srlz.i // ensure everybody knows psr.ic and psr.dt are back on + adds r8=(IA64_PT_REGS_R8_OFFSET-IA64_PT_REGS_R16_OFFSET),r2 + ;; + stf8 [r8]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) + adds r3=8,r2 // set up second base pointer for SAVE_REST + ;; + SAVE_REST + ;; // avoid WAW on r2 & r3 + + mov r3=255 + adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 + adds r2=IA64_TASK_FLAGS_OFFSET,r13 // r2 = ¤t->flags + + ;; + cmp.geu.unc p6,p7=r3,r15 // (syscall > 0 && syscall <= 1024+255) ? + movl r16=sys_call_table + ;; +(p6) shladd r16=r15,3,r16 + movl r15=ia64_ret_from_syscall +(p7) adds r16=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall + ;; + ld8 r16=[r16] // load address of syscall entry point + mov rp=r15 // set the real return addr + ;; + ld8 r2=[r2] // r2 = current->flags + mov b6=r16 + + // arrange things so we skip over break instruction when returning: + + adds r16=16,sp // get pointer to cr_ipsr + adds r17=24,sp // get pointer to cr_iip + ;; + ld8 r18=[r16] // fetch cr_ipsr + tbit.z p8,p0=r2,5 // (current->flags & PF_TRACESYS) == 0? + ;; + ld8 r19=[r17] // fetch cr_iip + extr.u r20=r18,41,2 // extract ei field + ;; + cmp.eq p6,p7=2,r20 // isr.ei==2? + adds r19=16,r19 // compute address of next bundle + ;; +(p6) mov r20=0 // clear ei to 0 +(p7) adds r20=1,r20 // increment ei to next slot + ;; +(p6) st8 [r17]=r19 // store new cr.iip if cr.isr.ei wrapped around + dep r18=r20,r18,41,2 // insert new ei into cr.isr + ;; + st8 [r16]=r18 // store new value for cr.isr + +(p8) br.call.sptk.few b6=b6 // ignore this return addr + br.call.sptk.few rp=ia64_trace_syscall // rp will be overwritten (ignored) + // NOT REACHED + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) + rsm psr.dt // avoid nested faults due to TLB misses... + ;; + srlz.d // ensure everyone knows psr.dt is off... + mov r31=pr // prepare to save predicates + ;; + + SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 + ssm psr.ic | psr.dt // turn interrupt collection and data translation back on + ;; + adds r3=8,r2 // set up second base pointer for SAVE_REST + cmp.eq pEOI,p0=r0,r0 // set pEOI flag so that ia64_leave_kernel writes cr.eoi + srlz.i // ensure everybody knows psr.ic and psr.dt are back on + ;; + SAVE_REST + ;; + alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + mov out0=r0 // defer reading of cr.ivr to handle_irq... +#else + mov out0=cr.ivr // pass cr.ivr as first arg +#endif + add out1=16,sp // pass pointer to pt_regs as second arg + ;; + srlz.d // make sure we see the effect of cr.ivr + movl r14=ia64_leave_kernel + ;; + mov rp=r14 + br.call.sptk.few b6=ia64_handle_irq + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3400 Entry 13 (size 64 bundles) Reserved + FAULT(13) + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3800 Entry 14 (size 64 bundles) Reserved + FAULT(14) + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x3c00 Entry 15 (size 64 bundles) Reserved + FAULT(15) + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4000 Entry 16 (size 64 bundles) Reserved + FAULT(16) + +#ifdef CONFIG_IA32_SUPPORT + + // There is no particular reason for this code to be here, other than that + // there happens to be space here that would go unused otherwise. If this + // fault ever gets "unreserved", simply moved the following code to a more + // suitable spot... + + // IA32 interrupt entry point + +dispatch_to_ia32_handler: + SAVE_MIN + ;; + mov r14=cr.isr + ssm psr.ic | psr.dt + srlz.d // guarantee that interrupt collection is enabled + ;; +(p15) ssm psr.i + ;; + srlz.d + adds r3=8,r2 // Base pointer for SAVE_REST + ;; + SAVE_REST + ;; + mov r15=0x80 + shr r14=r14,16 // Get interrupt number + ;; + cmp.ne p6,p0=r14,r15 +(p6) br.call.dpnt.few b6=non_ia32_syscall + + adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions + + ;; + alloc r15=ar.pfs,0,0,6,0 // must first in an insn group + ;; + ld4 r8=[r14],8 // r8 == EAX (syscall number) + mov r15=0xff + ;; + cmp.ltu.unc p6,p7=r8,r15 + ld4 out1=[r14],8 // r9 == ecx + ;; + ld4 out2=[r14],8 // r10 == edx + ;; + ld4 out0=[r14] // r11 == ebx + adds r14=(IA64_PT_REGS_R8_OFFSET-(8*3)) + 16,sp + ;; + ld4 out5=[r14],8 // r13 == ebp + ;; + ld4 out3=[r14],8 // r14 == esi + adds r2=IA64_TASK_FLAGS_OFFSET,r13 // r2 = ¤t->flags + ;; + ld4 out4=[r14] // R15 == edi + movl r16=ia32_syscall_table + ;; +(p6) shladd r16=r8,3,r16 // Force ni_syscall if not valid syscall number + ld8 r2=[r2] // r2 = current->flags + ;; + ld8 r16=[r16] + tbit.z p8,p0=r2,5 // (current->flags & PF_TRACESYS) == 0? + ;; + movl r15=ia32_ret_from_syscall + mov b6=r16 + ;; + mov rp=r15 +(p8) br.call.sptk.few b6=b6 + br.call.sptk.few rp=ia32_trace_syscall // rp will be overwritten (ignored) + +non_ia32_syscall: + alloc r15=ar.pfs,0,0,2,0 + mov out0=r14 // interrupt # + add out1=16,sp // pointer to pt_regs + ;; // avoid WAW on CFM + br.call.sptk.few rp=ia32_bad_interrupt + ;; + movl r15=ia64_leave_kernel + ;; + mov rp=r15 + br.ret.sptk.many rp + +#endif /* CONFIG_IA32_SUPPORT */ + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4400 Entry 17 (size 64 bundles) Reserved + FAULT(17) + +non_syscall: + +#ifdef CONFIG_KDB + mov r17=__IA64_BREAK_KDB + ;; + cmp.eq p8,p0=r16,r17 // is this a kernel breakpoint? +#endif + + SAVE_MIN_WITH_COVER + + // There is no particular reason for this code to be here, other than that + // there happens to be space here that would go unused otherwise. If this + // fault ever gets "unreserved", simply moved the following code to a more + // suitable spot... + + mov r8=cr.iim // get break immediate (must be done while psr.ic is off) + adds r3=8,r2 // set up second base pointer for SAVE_REST + + // turn interrupt collection and data translation back on: + ssm psr.ic | psr.dt + srlz.d // guarantee that interrupt collection is enabled + ;; +(p15) ssm psr.i // restore psr.i + ;; + srlz.i // ensure everybody knows psr.ic and psr.dt are back on + movl r15=ia64_leave_kernel + ;; + alloc r14=ar.pfs,0,0,2,0 + mov out0=r8 // break number + add out1=16,sp // pointer to pt_regs + ;; + SAVE_REST + mov rp=r15 + ;; +#ifdef CONFIG_KDB +(p8) br.call.sptk.few b6=ia64_invoke_kdb +#endif + br.call.sptk.few b6=ia64_bad_break // avoid WAW on CFM and ignore return addr + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4800 Entry 18 (size 64 bundles) Reserved + FAULT(18) + + // There is no particular reason for this code to be here, other than that + // there happens to be space here that would go unused otherwise. If this + // fault ever gets "unreserved", simply moved the following code to a more + // suitable spot... + +dispatch_unaligned_handler: + SAVE_MIN_WITH_COVER + ;; + // + // we can't have the alloc while psr.ic is cleared because + // we might get a mandatory RSE (when you reach the end of the + // rotating partition when doing the alloc) spill which could cause + // a page fault on the kernel virtual address and the handler + // wouldn't get the state to recover. + // + mov r15=cr.ifa + ssm psr.ic | psr.dt + srlz.d // guarantee that interrupt collection is enabled + ;; +(p15) ssm psr.i // restore psr.i + ;; + srlz.i + adds r3=8,r2 // set up second base pointer + ;; + SAVE_REST + ;; + alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!) + ;; // avoid WAW on r14 + movl r14=ia64_leave_kernel + mov out0=r15 // out0 = faulting address + adds out1=16,sp // out1 = pointer to pt_regs + ;; + mov rp=r14 + br.sptk.few ia64_prepare_handle_unaligned + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x4c00 Entry 19 (size 64 bundles) Reserved + FAULT(19) + + // There is no particular reason for this code to be here, other than that + // there happens to be space here that would go unused otherwise. If this + // fault ever gets "unreserved", simply moved the following code to a more + // suitable spot... + +dispatch_to_fault_handler: + // + // Input: + // psr.ic: off + // psr.dt: off + // r19: fault vector number (e.g., 24 for General Exception) + // r31: contains saved predicates (pr) + // + SAVE_MIN_WITH_COVER_R19 + // + // Copy control registers to temporary registers, then turn on psr bits, + // then copy the temporary regs to the output regs. We have to do this + // because the "alloc" can cause a mandatory store which could lead to + // an "Alt DTLB" fault which we can handle only if psr.ic is on. + // + mov r8=cr.isr + mov r9=cr.ifa + mov r10=cr.iim + mov r11=cr.itir + ;; + ssm psr.ic | psr.dt + srlz.d // guarantee that interrupt collection is enabled + ;; +(p15) ssm psr.i // restore psr.i + adds r3=8,r2 // set up second base pointer for SAVE_REST + ;; + srlz.i // must precede "alloc"! + ;; + alloc r14=ar.pfs,0,0,5,0 // must be first in insn group + mov out0=r15 + mov out1=r8 + mov out2=r9 + mov out3=r10 + mov out4=r11 + ;; + SAVE_REST + movl r14=ia64_leave_kernel + ;; + mov rp=r14 +#ifdef CONFIG_KDB + br.call.sptk.few b6=ia64_invoke_kdb_fault_handler +#else + br.call.sptk.few b6=ia64_fault +#endif +// +// --- End of long entries, Beginning of short entries +// + + .align 1024 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49) + mov r16=cr.ifa + rsm psr.dt +#if 0 + // If you disable this, you MUST re-enable to update_mmu_cache() code in pgtable.h + mov r17=_PAGE_SIZE_4K<<2 + ;; + ptc.l r16,r17 +#endif + ;; + mov r31=pr + srlz.d + br.cond.sptk.many page_fault + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5100 Entry 21 (size 16 bundles) Key Permission (13,25,52) + mov r16=cr.ifa + rsm psr.dt + mov r31=pr + ;; + srlz.d + br.cond.sptk.many page_fault + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5200 Entry 22 (size 16 bundles) Instruction Access Rights (26) + mov r16=cr.ifa + rsm psr.dt + mov r31=pr + ;; + srlz.d + br.cond.sptk.many page_fault + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) + mov r16=cr.ifa + rsm psr.dt + mov r31=pr + ;; + srlz.d + br.cond.sptk.many page_fault + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5400 Entry 24 (size 16 bundles) General Exception (5,32,34,36,38,39) + FAULT(24) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5500 Entry 25 (size 16 bundles) Disabled FP-Register (35) + rsm psr.dt | psr.dfh // ensure we can access fph + ;; + srlz.d + mov r31=pr + mov r19=25 + br.cond.sptk.many dispatch_to_fault_handler + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50) + FAULT(26) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5700 Entry 27 (size 16 bundles) Speculation (40) + // + // A [f]chk.[as] instruction needs to take the branch to + // the recovery code but this part of the architecture is + // not implemented in hardware on some CPUs, such as Itanium. + // Thus, in general we need to emulate the behavior. + // IIM contains the relative target (not yet sign extended). + // So after sign extending it we simply add it to IIP. + // We also need to reset the EI field of the IPSR to zero, + // i.e., the slot to restart into. + // + // cr.imm contains zero_ext(imm21) + // + mov r18=cr.iim + ;; + mov r17=cr.iip + shl r18=r18,43 // put sign bit in position (43=64-21) + ;; + + mov r16=cr.ipsr + shr r18=r18,39 // sign extend (39=43-4) + ;; + + add r17=r17,r18 // now add the offset + ;; + mov cr.iip=r17 + dep r16=0,r16,41,2 // clear EI + ;; + + mov cr.ipsr=r16 + ;; + + rfi;; // and go back (must be last insn in group) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5800 Entry 28 (size 16 bundles) Reserved + FAULT(28) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5900 Entry 29 (size 16 bundles) Debug (16,28,56) + FAULT(29) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5a00 Entry 30 (size 16 bundles) Unaligned Reference (57) + rsm psr.dt // avoid nested faults due to TLB misses... + mov r16=cr.ipsr + mov r31=pr // prepare to save predicates + ;; + srlz.d // ensure everyone knows psr.dt is off + mov r19=30 // error vector for fault_handler (when kernel) + extr.u r16=r16,32,2 // extract psr.cpl + ;; + cmp.eq p6,p7=r0,r16 // if kernel cpl then fault else emulate +(p7) br.cond.sptk.many dispatch_unaligned_handler +(p6) br.cond.sptk.many dispatch_to_fault_handler + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5b00 Entry 31 (size 16 bundles) Unsupported Data Reference (57) + FAULT(31) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5c00 Entry 32 (size 16 bundles) Floating-Point Fault (64) + FAULT(32) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5d00 Entry 33 (size 16 bundles) Floating Point Trap (66) + FAULT(33) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5e00 Entry 34 (size 16 bundles) Lower Privilege Tranfer Trap (66) + FAULT(34) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x5f00 Entry 35 (size 16 bundles) Taken Branch Trap (68) + FAULT(35) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6000 Entry 36 (size 16 bundles) Single Step Trap (69) + FAULT(36) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6100 Entry 37 (size 16 bundles) Reserved + FAULT(37) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6200 Entry 38 (size 16 bundles) Reserved + FAULT(38) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6300 Entry 39 (size 16 bundles) Reserved + FAULT(39) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6400 Entry 40 (size 16 bundles) Reserved + FAULT(40) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6500 Entry 41 (size 16 bundles) Reserved + FAULT(41) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6600 Entry 42 (size 16 bundles) Reserved + FAULT(42) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6700 Entry 43 (size 16 bundles) Reserved + FAULT(43) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6800 Entry 44 (size 16 bundles) Reserved + FAULT(44) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6900 Entry 45 (size 16 bundles) IA-32 Exeception (17,18,29,41,42,43,44,58,60,61,62,72,73,75,76,77) + FAULT(45) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6a00 Entry 46 (size 16 bundles) IA-32 Intercept (30,31,59,70,71) + FAULT(46) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6b00 Entry 47 (size 16 bundles) IA-32 Interrupt (74) +#ifdef CONFIG_IA32_SUPPORT + rsm psr.dt + ;; + srlz.d + mov r31=pr + br.cond.sptk.many dispatch_to_ia32_handler +#else + FAULT(47) +#endif + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6c00 Entry 48 (size 16 bundles) Reserved + FAULT(48) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6d00 Entry 49 (size 16 bundles) Reserved + FAULT(49) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6e00 Entry 50 (size 16 bundles) Reserved + FAULT(50) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x6f00 Entry 51 (size 16 bundles) Reserved + FAULT(51) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7000 Entry 52 (size 16 bundles) Reserved + FAULT(52) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7100 Entry 53 (size 16 bundles) Reserved + FAULT(53) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7200 Entry 54 (size 16 bundles) Reserved + FAULT(54) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7300 Entry 55 (size 16 bundles) Reserved + FAULT(55) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7400 Entry 56 (size 16 bundles) Reserved + FAULT(56) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7500 Entry 57 (size 16 bundles) Reserved + FAULT(57) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7600 Entry 58 (size 16 bundles) Reserved + FAULT(58) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7700 Entry 59 (size 16 bundles) Reserved + FAULT(59) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7800 Entry 60 (size 16 bundles) Reserved + FAULT(60) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7900 Entry 61 (size 16 bundles) Reserved + FAULT(61) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7a00 Entry 62 (size 16 bundles) Reserved + FAULT(62) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7b00 Entry 63 (size 16 bundles) Reserved + FAULT(63) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7c00 Entry 64 (size 16 bundles) Reserved + FAULT(64) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7d00 Entry 65 (size 16 bundles) Reserved + FAULT(65) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7e00 Entry 66 (size 16 bundles) Reserved + FAULT(66) + + .align 256 +///////////////////////////////////////////////////////////////////////////////////////// +// 0x7f00 Entry 67 (size 16 bundles) Reserved + FAULT(67) diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/machvec.c linux/arch/ia64/kernel/machvec.c --- v2.3.42/linux/arch/ia64/kernel/machvec.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/machvec.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,48 @@ +#include + +#include +#include + +struct ia64_machine_vector ia64_mv; + +void +machvec_noop (void) +{ +} + +/* + * Most platforms use this routine for mapping page frame addresses + * into a memory map index. + */ +unsigned long +map_nr_dense (unsigned long addr) +{ + return MAP_NR_DENSE(addr); +} + +static struct ia64_machine_vector * +lookup_machvec (const char *name) +{ + extern struct ia64_machine_vector machvec_start[]; + extern struct ia64_machine_vector machvec_end[]; + struct ia64_machine_vector *mv; + + for (mv = machvec_start; mv < machvec_end; ++mv) + if (strcmp (mv->name, name) == 0) + return mv; + + return 0; +} + +void +machvec_init (const char *name) +{ + struct ia64_machine_vector *mv; + + mv = lookup_machvec(name); + if (!mv) { + panic("generic kernel failed to find machine vector for platform %s!", name); + } + ia64_mv = *mv; + printk("booting generic kernel on platform %s\n", name); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c --- v2.3.42/linux/arch/ia64/kernel/mca.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/mca.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,842 @@ +/* + * File: mca.c + * Purpose: Generic MCA handling layer + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Vijay Chander(vijay@engr.sgi.com) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +ia64_mc_info_t ia64_mc_info; +ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; +ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; +u64 ia64_mca_proc_state_dump[256]; +u64 ia64_mca_stack[1024]; +u64 ia64_mca_stackframe[32]; +u64 ia64_mca_bspstore[1024]; + +static void ia64_mca_cmc_vector_setup(int enable, + int_vector_t cmc_vector); +static void ia64_mca_wakeup_ipi_wait(void); +static void ia64_mca_wakeup(int cpu); +static void ia64_mca_wakeup_all(void); +static void ia64_log_init(int,int); +static void ia64_log_get(int,int, prfunc_t); +static void ia64_log_clear(int,int,int, prfunc_t); + +/* + * ia64_mca_cmc_vector_setup + * Setup the correctable machine check vector register in the processor + * Inputs + * Enable (1 - enable cmc interrupt , 0 - disable) + * CMC handler entry point (if enabled) + * + * Outputs + * None + */ +static void +ia64_mca_cmc_vector_setup(int enable, + int_vector_t cmc_vector) +{ + cmcv_reg_t cmcv; + + cmcv.cmcv_regval = 0; + cmcv.cmcv_mask = enable; + cmcv.cmcv_vector = cmc_vector; + ia64_set_cmcv(cmcv.cmcv_regval); +} + + +#if defined(MCA_TEST) + +sal_log_processor_info_t slpi_buf; + +void +mca_test(void) +{ + slpi_buf.slpi_valid.slpi_psi = 1; + slpi_buf.slpi_valid.slpi_cache_check = 1; + slpi_buf.slpi_valid.slpi_tlb_check = 1; + slpi_buf.slpi_valid.slpi_bus_check = 1; + slpi_buf.slpi_valid.slpi_minstate = 1; + slpi_buf.slpi_valid.slpi_bank1_gr = 1; + slpi_buf.slpi_valid.slpi_br = 1; + slpi_buf.slpi_valid.slpi_cr = 1; + slpi_buf.slpi_valid.slpi_ar = 1; + slpi_buf.slpi_valid.slpi_rr = 1; + slpi_buf.slpi_valid.slpi_fr = 1; + + ia64_os_mca_dispatch(); +} + +#endif /* #if defined(MCA_TEST) */ + +/* + * mca_init + * Do all the mca specific initialization on a per-processor basis. + * + * 1. Register spinloop and wakeup request interrupt vectors + * + * 2. Register OS_MCA handler entry point + * + * 3. Register OS_INIT handler entry point + * + * 4. Initialize CMCV register to enable/disable CMC interrupt on the + * processor and hook a handler in the platform-specific mca_init. + * + * 5. Initialize MCA/CMC/INIT related log buffers maintained by the OS. + * + * Inputs + * None + * Outputs + * None + */ +void __init +mca_init(void) +{ + int i; + + MCA_DEBUG("mca_init : begin\n"); + /* Clear the Rendez checkin flag for all cpus */ + for(i = 0 ; i < IA64_MAXCPUS; i++) + ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; + + /* NOTE : The actual irqs for the rendez, wakeup and + * cmc interrupts are requested in the platform-specific + * mca initialization code. + */ + /* + * Register the rendezvous spinloop and wakeup mechanism with SAL + */ + + /* Register the rendezvous interrupt vector with SAL */ + if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_RENDEZ_INT_VECTOR, + IA64_MCA_RENDEZ_TIMEOUT)) + return; + + /* Register the wakeup interrupt vector with SAL */ + if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_WAKEUP_INT_VECTOR, + 0)) + return; + + MCA_DEBUG("mca_init : registered mca rendezvous spinloop and wakeup mech.\n"); + /* + * Setup the correctable machine check vector + */ + ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE, + IA64_MCA_CMC_INT_VECTOR); + + MCA_DEBUG("mca_init : correctable mca vector setup done\n"); + + ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); + ia64_mc_info.imi_mca_handler_size = + __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); + /* Register the os mca handler with SAL */ + if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, + ia64_mc_info.imi_mca_handler, + __pa(ia64_get_gp()), + ia64_mc_info.imi_mca_handler_size, + 0,0,0)) + + return; + + MCA_DEBUG("mca_init : registered os mca handler with SAL\n"); + + ia64_mc_info.imi_monarch_init_handler = __pa(ia64_monarch_init_handler); + ia64_mc_info.imi_monarch_init_handler_size = IA64_INIT_HANDLER_SIZE; + ia64_mc_info.imi_slave_init_handler = __pa(ia64_slave_init_handler); + ia64_mc_info.imi_slave_init_handler_size = IA64_INIT_HANDLER_SIZE; + /* Register the os init handler with SAL */ + if (ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, + ia64_mc_info.imi_monarch_init_handler, + __pa(ia64_get_gp()), + ia64_mc_info.imi_monarch_init_handler_size, + ia64_mc_info.imi_slave_init_handler, + __pa(ia64_get_gp()), + ia64_mc_info.imi_slave_init_handler_size)) + + + return; + + MCA_DEBUG("mca_init : registered os init handler with SAL\n"); + + /* Initialize the areas set aside by the OS to buffer the + * platform/processor error states for MCA/INIT/CMC + * handling. + */ + ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR); + ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM); + ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR); + ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM); + ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR); + ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); + + mca_init_platform(); + + MCA_DEBUG("mca_init : platform-specific mca handling setup done\n"); + +#if defined(MCA_TEST) + mca_test(); +#endif /* #if defined(MCA_TEST) */ + + printk("Mca related initialization done\n"); +} + +/* + * ia64_mca_wakeup_ipi_wait + * Wait for the inter-cpu interrupt to be sent by the + * monarch processor once it is done with handling the + * MCA. + * Inputs + * None + * Outputs + * None + */ +void +ia64_mca_wakeup_ipi_wait(void) +{ + int irr_num = (IA64_MCA_WAKEUP_INT_VECTOR >> 6); + int irr_bit = (IA64_MCA_WAKEUP_INT_VECTOR & 0x3f); + u64 irr = 0; + + do { + switch(irr_num) { + case 0: + irr = ia64_get_irr0(); + break; + case 1: + irr = ia64_get_irr1(); + break; + case 2: + irr = ia64_get_irr2(); + break; + case 3: + irr = ia64_get_irr3(); + break; + } + } while (!(irr & (1 << irr_bit))) ; +} + +/* + * ia64_mca_wakeup + * Send an inter-cpu interrupt to wake-up a particular cpu + * and mark that cpu to be out of rendez. + * Inputs + * cpuid + * Outputs + * None + */ +void +ia64_mca_wakeup(int cpu) +{ + ipi_send(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT); + ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; + +} +/* + * ia64_mca_wakeup_all + * Wakeup all the cpus which have rendez'ed previously. + * Inputs + * None + * Outputs + * None + */ +void +ia64_mca_wakeup_all(void) +{ + int cpu; + + /* Clear the Rendez checkin flag for all cpus */ + for(cpu = 0 ; cpu < IA64_MAXCPUS; cpu++) + if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE) + ia64_mca_wakeup(cpu); + +} +/* + * ia64_mca_rendez_interrupt_handler + * This is handler used to put slave processors into spinloop + * while the monarch processor does the mca handling and later + * wake each slave up once the monarch is done. + * Inputs + * None + * Outputs + * None + */ +void +ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) +{ + int flags; + /* Mask all interrupts */ + save_and_cli(flags); + + ia64_mc_info.imi_rendez_checkin[ia64_get_cpuid(0)] = IA64_MCA_RENDEZ_CHECKIN_DONE; + /* Register with the SAL monarch that the slave has + * reached SAL + */ + ia64_sal_mc_rendez(); + + /* Wait for the wakeup IPI from the monarch + * This waiting is done by polling on the wakeup-interrupt + * vector bit in the processor's IRRs + */ + ia64_mca_wakeup_ipi_wait(); + + /* Enable all interrupts */ + restore_flags(flags); + + +} + + +/* + * ia64_mca_wakeup_int_handler + * The interrupt handler for processing the inter-cpu interrupt to the + * slave cpu which was spinning in the rendez loop. + * Since this spinning is done by turning off the interrupts and + * polling on the wakeup-interrupt bit in the IRR, there is + * nothing useful to be done in the handler. + * Inputs + * wakeup_irq (Wakeup-interrupt bit) + * arg (Interrupt handler specific argument) + * ptregs (Exception frame at the time of the interrupt) + * Outputs + * + */ +void +ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) +{ + +} + +/* + * ia64_return_to_sal_check + * This is function called before going back from the OS_MCA handler + * to the OS_MCA dispatch code which finally takes the control back + * to the SAL. + * The main purpose of this routine is to setup the OS_MCA to SAL + * return state which can be used by the OS_MCA dispatch code + * just before going back to SAL. + * Inputs + * None + * Outputs + * None + */ + +void +ia64_return_to_sal_check(void) +{ + /* Copy over some relevant stuff from the sal_to_os_mca_handoff + * so that it can be used at the time of os_mca_to_sal_handoff + */ + ia64_os_to_sal_handoff_state.imots_sal_gp = + ia64_sal_to_os_handoff_state.imsto_sal_gp; + + ia64_os_to_sal_handoff_state.imots_sal_check_ra = + ia64_sal_to_os_handoff_state.imsto_sal_check_ra; + + /* For now ignore the MCA */ + ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; +} +/* + * ia64_mca_ucmc_handler + * This is uncorrectable machine check handler called from OS_MCA + * dispatch code which is in turn called from SAL_CHECK(). + * This is the place where the core of OS MCA handling is done. + * Right now the logs are extracted and displayed in a well-defined + * format. This handler code is supposed to be run only on the + * monarch processor. Once the monarch is done with MCA handling + * further MCA logging is enabled by clearing logs. + * Monarch also has the duty of sending wakeup-IPIs to pull the + * slave processors out of rendez. spinloop. + * Inputs + * None + * Outputs + * None + */ +void +ia64_mca_ucmc_handler(void) +{ + + /* Get the MCA processor log */ + ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + /* Get the MCA platform log */ + ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); + + ia64_log_print(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + + /* + * Do some error handling - Platform-specific mca handler is called at this point + */ + + mca_handler_platform() ; + + /* Clear the SAL MCA logs */ + ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, 1, printk); + ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, 1, printk); + + /* Wakeup all the processors which are spinning in the rendezvous + * loop. + */ + ia64_mca_wakeup_all(); + ia64_return_to_sal_check(); +} + +/* + * SAL to OS entry point for INIT on the monarch processor + * This has been defined for registration purposes with SAL + * as a part of mca_init. + */ +void +ia64_monarch_init_handler() +{ +} +/* + * SAL to OS entry point for INIT on the slave processor + * This has been defined for registration purposes with SAL + * as a part of mca_init. + */ + +void +ia64_slave_init_handler() +{ +} +/* + * ia64_mca_cmc_int_handler + * This is correctable machine check interrupt handler. + * Right now the logs are extracted and displayed in a well-defined + * format. + * Inputs + * None + * Outputs + * None + */ +void +ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) +{ + /* Get the CMC processor log */ + ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + /* Get the CMC platform log */ + ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk); + + + ia64_log_print(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk); + cmci_handler_platform(cmc_irq, arg, ptregs); + + /* Clear the CMC SAL logs now that they have been saved in the OS buffer */ + ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR); + ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM); +} + +/* + * IA64_MCA log support + */ +#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */ +#define IA64_MAX_LOG_TYPES 3 /* MCA, CMC, INIT */ +#define IA64_MAX_LOG_SUBTYPES 2 /* Processor, Platform */ + +typedef struct ia64_state_log_s { + spinlock_t isl_lock; + int isl_index; + sal_log_header_t isl_log[IA64_MAX_LOGS]; + +} ia64_state_log_t; + +static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES]; + +#define IA64_LOG_LOCK_INIT(it, sit) spin_lock_init(&ia64_state_log[it][sit].isl_lock) +#define IA64_LOG_LOCK(it, sit) spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s) +#define IA64_LOG_UNLOCK(it, sit) spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\ + s) +#define IA64_LOG_NEXT_INDEX(it, sit) ia64_state_log[it][sit].isl_index +#define IA64_LOG_CURR_INDEX(it, sit) 1 - ia64_state_log[it][sit].isl_index +#define IA64_LOG_INDEX_INC(it, sit) \ + ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index +#define IA64_LOG_INDEX_DEC(it, sit) \ + ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index +#define IA64_LOG_NEXT_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)])) +#define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)])) + +/* + * ia64_log_init + * Reset the OS ia64 log buffer + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) + * Outputs : None + */ +void +ia64_log_init(int sal_info_type, int sal_sub_info_type) +{ + IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type); + IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0; + memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0, + sizeof(sal_log_header_t) * IA64_MAX_LOGS); +} + +/* + * ia64_log_get + * Get the current MCA log from SAL and copy it into the OS log buffer. + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) + * Outputs : None + * + */ +void +ia64_log_get(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) +{ + sal_log_header_t *log_buffer; + int s; + + IA64_LOG_LOCK(sal_info_type, sal_sub_info_type); + + + /* Get the process state information */ + log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type); + + if (ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer)) + prfunc("ia64_mca_log_get : Getting processor log failed\n"); + + IA64_LOG_INDEX_INC(sal_info_type, sal_sub_info_type); + + IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); + +} + +/* + * ia64_log_clear + * Clear the current MCA log from SAL and dpending on the clear_os_buffer flags + * clear the OS log buffer also + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) + * clear_os_buffer + * prfunc (print function) + * Outputs : None + * + */ +void +ia64_log_clear(int sal_info_type, int sal_sub_info_type, int clear_os_buffer, prfunc_t prfunc) +{ + if (ia64_sal_clear_state_info(sal_info_type, sal_sub_info_type)) + prfunc("ia64_mca_log_get : Clearing processor log failed\n"); + + if (clear_os_buffer) { + sal_log_header_t *log_buffer; + int s; + + IA64_LOG_LOCK(sal_info_type, sal_sub_info_type); + + /* Get the process state information */ + log_buffer = IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type); + + memset(log_buffer, 0, sizeof(sal_log_header_t)); + + IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type); + + IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type); + } + +} + +/* + * ia64_log_processor_regs_print + * Print the contents of the saved processor register(s) in the format + * [] + * + * Inputs : regs (Register save buffer) + * reg_num (# of registers) + * reg_class (application/banked/control/bank1_general) + * reg_prefix (ar/br/cr/b1_gr) + * Outputs : None + * + */ +void +ia64_log_processor_regs_print(u64 *regs, + int reg_num, + char *reg_class, + char *reg_prefix, + prfunc_t prfunc) +{ + int i; + + prfunc("+%s Registers\n", reg_class); + for (i = 0; i < reg_num; i++) + prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]); +} + +static char *pal_mesi_state[] = { + "Invalid", + "Shared", + "Exclusive", + "Modified", + "Reserved1", + "Reserved2", + "Reserved3", + "Reserved4" +}; + +static char *pal_cache_op[] = { + "Unknown", + "Move in", + "Cast out", + "Coherency check", + "Internal", + "Instruction fetch", + "Implicit Writeback", + "Reserved" +}; + +/* + * ia64_log_cache_check_info_print + * Display the machine check information related to cache error(s). + * Inputs : i (Multiple errors are logged, i - index of logged error) + * info (Machine check info logged by the PAL and later + * captured by the SAL) + * target_addr (Address which caused the cache error) + * Outputs : None + */ +void +ia64_log_cache_check_info_print(int i, + pal_cache_check_info_t info, + u64 target_addr, + prfunc_t prfunc) +{ + prfunc("+ Cache check info[%d]\n+", i); + prfunc(" Level: L%d",info.level); + if (info.mv) + prfunc(" ,Mesi: %s",pal_mesi_state[info.mesi]); + prfunc(" ,Index: %d,", info.index); + if (info.ic) + prfunc(" ,Cache: Instruction"); + if (info.dc) + prfunc(" ,Cache: Data"); + if (info.tl) + prfunc(" ,Line: Tag"); + if (info.dl) + prfunc(" ,Line: Data"); + prfunc(" ,Operation: %s,", pal_cache_op[info.op]); + if (info.wv) + prfunc(" ,Way: %d,", info.way); + if (info.tv) + prfunc(" ,Target Addr: 0x%lx", target_addr); + if (info.mc) + prfunc(" ,MC: Corrected"); + prfunc("\n"); +} + +/* + * ia64_log_tlb_check_info_print + * Display the machine check information related to tlb error(s). + * Inputs : i (Multiple errors are logged, i - index of logged error) + * info (Machine check info logged by the PAL and later + * captured by the SAL) + * Outputs : None + */ + +void +ia64_log_tlb_check_info_print(int i, + pal_tlb_check_info_t info, + prfunc_t prfunc) +{ + prfunc("+ TLB Check Info [%d]\n+", i); + if (info.itc) + prfunc(" Failure: Instruction Translation Cache"); + if (info.dtc) + prfunc(" Failure: Data Translation Cache"); + if (info.itr) { + prfunc(" Failure: Instruction Translation Register"); + prfunc(" ,Slot: %d", info.tr_slot); + } + if (info.dtr) { + prfunc(" Failure: Data Translation Register"); + prfunc(" ,Slot: %d", info.tr_slot); + } + if (info.mc) + prfunc(" ,MC: Corrected"); + prfunc("\n"); +} + +/* + * ia64_log_bus_check_info_print + * Display the machine check information related to bus error(s). + * Inputs : i (Multiple errors are logged, i - index of logged error) + * info (Machine check info logged by the PAL and later + * captured by the SAL) + * req_addr (Address of the requestor of the transaction) + * resp_addr (Address of the responder of the transaction) + * target_addr (Address where the data was to be delivered to or + * obtained from) + * Outputs : None + */ +void +ia64_log_bus_check_info_print(int i, + pal_bus_check_info_t info, + u64 req_addr, + u64 resp_addr, + u64 targ_addr, + prfunc_t prfunc) +{ + prfunc("+ BUS Check Info [%d]\n+", i); + prfunc(" Status Info: %d", info.bsi); + prfunc(" ,Severity: %d", info.sev); + prfunc(" ,Transaction Type: %d", info.type); + prfunc(" ,Transaction Size: %d", info.size); + if (info.cc) + prfunc(" ,Cache-cache-transfer"); + if (info.ib) + prfunc(" ,Error: Internal"); + if (info.eb) + prfunc(" ,Error: External"); + if (info.mc) + prfunc(" ,MC: Corrected"); + if (info.tv) + prfunc(" ,Target Address: 0x%lx", targ_addr); + if (info.rq) + prfunc(" ,Requestor Address: 0x%lx", req_addr); + if (info.tv) + prfunc(" ,Responder Address: 0x%lx", resp_addr); + prfunc("\n"); +} + +/* + * ia64_log_processor_info_print + * Display the processor-specific information logged by PAL as a part + * of MCA or INIT or CMC. + * Inputs : lh (Pointer of the sal log header which specifies the format + * of SAL state info as specified by the SAL spec). + * Outputs : None + */ +void +ia64_log_processor_info_print(sal_log_header_t *lh, prfunc_t prfunc) +{ + sal_log_processor_info_t *slpi; + int i; + + if (!lh) + return; + + if (lh->slh_log_type != SAL_SUB_INFO_TYPE_PROCESSOR) + return; + +#if defined(MCA_TEST) + slpi = &slpi_buf; +#else + slpi = (sal_log_processor_info_t *)lh->slh_log_dev_spec_info; +#endif /#if defined(MCA_TEST) */ + + if (!slpi) { + prfunc("No Processor Error Log found\n"); + return; + } + + /* Print branch register contents if valid */ + if (slpi->slpi_valid.slpi_br) + ia64_log_processor_regs_print(slpi->slpi_br, 8, "Branch", "br", prfunc); + + /* Print control register contents if valid */ + if (slpi->slpi_valid.slpi_cr) + ia64_log_processor_regs_print(slpi->slpi_cr, 128, "Control", "cr", prfunc); + + /* Print application register contents if valid */ + if (slpi->slpi_valid.slpi_ar) + ia64_log_processor_regs_print(slpi->slpi_br, 128, "Application", "ar", prfunc); + + /* Print region register contents if valid */ + if (slpi->slpi_valid.slpi_rr) + ia64_log_processor_regs_print(slpi->slpi_rr, 8, "Region", "rr", prfunc); + + /* Print floating-point register contents if valid */ + if (slpi->slpi_valid.slpi_fr) + ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr", + prfunc); + + /* Print bank1-gr NAT register contents if valid */ + ia64_log_processor_regs_print(&slpi->slpi_bank1_nat_bits, 1, "NAT", "nat", prfunc); + + /* Print bank 1 register contents if valid */ + if (slpi->slpi_valid.slpi_bank1_gr) + ia64_log_processor_regs_print(slpi->slpi_bank1_gr, 16, "Bank1-General", "gr", + prfunc); + + /* Print the cache check information if any*/ + for (i = 0 ; i < MAX_CACHE_ERRORS; i++) + ia64_log_cache_check_info_print(i, + slpi->slpi_cache_check_info[i].slpi_cache_check, + slpi->slpi_cache_check_info[i].slpi_target_address, + prfunc); + /* Print the tlb check information if any*/ + for (i = 0 ; i < MAX_TLB_ERRORS; i++) + ia64_log_tlb_check_info_print(i,slpi->slpi_tlb_check_info[i], prfunc); + + /* Print the bus check information if any*/ + for (i = 0 ; i < MAX_BUS_ERRORS; i++) + ia64_log_bus_check_info_print(i, + slpi->slpi_bus_check_info[i].slpi_bus_check, + slpi->slpi_bus_check_info[i].slpi_requestor_addr, + slpi->slpi_bus_check_info[i].slpi_responder_addr, + slpi->slpi_bus_check_info[i].slpi_target_addr, + prfunc); + +} + +/* + * ia64_log_print + * Display the contents of the OS error log information + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC}) + * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM}) + * Outputs : None + */ +void +ia64_log_print(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc) +{ + char *info_type, *sub_info_type; + + switch(sal_info_type) { + case SAL_INFO_TYPE_MCA: + info_type = "MCA"; + break; + case SAL_INFO_TYPE_INIT: + info_type = "INIT"; + break; + case SAL_INFO_TYPE_CMC: + info_type = "CMC"; + break; + default: + info_type = "UNKNOWN"; + break; + } + + switch(sal_sub_info_type) { + case SAL_SUB_INFO_TYPE_PROCESSOR: + sub_info_type = "PROCESSOR"; + break; + case SAL_SUB_INFO_TYPE_PLATFORM: + sub_info_type = "PLATFORM"; + break; + default: + sub_info_type = "UNKNOWN"; + break; + } + + prfunc("+BEGIN HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type); + if (sal_sub_info_type == SAL_SUB_INFO_TYPE_PROCESSOR) + ia64_log_processor_info_print( + IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type), + prfunc); + else + log_print_platform(IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type),prfunc); + prfunc("+END HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S --- v2.3.42/linux/arch/ia64/kernel/mca_asm.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/mca_asm.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,621 @@ +#include +#include +#include +#include + + .psr abi64 + .psr lsb + .lsb + +/* + * SAL_TO_OS_MCA_HANDOFF_STATE + * 1. GR1 = OS GP + * 2. GR8 = PAL_PROC physical address + * 3. GR9 = SAL_PROC physical address + * 4. GR10 = SAL GP (physical) + * 5. GR11 = Rendez state + * 6. GR12 = Return address to location within SAL_CHECK + */ +#define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ + movl _tmp=ia64_sal_to_os_handoff_state;; \ + st8 [_tmp]=r1,0x08;; \ + st8 [_tmp]=r8,0x08;; \ + st8 [_tmp]=r9,0x08;; \ + st8 [_tmp]=r10,0x08;; \ + st8 [_tmp]=r11,0x08;; \ + st8 [_tmp]=r12,0x08;; + +/* + * OS_MCA_TO_SAL_HANDOFF_STATE + * 1. GR8 = OS_MCA status + * 2. GR9 = SAL GP (physical) + * 3. GR22 = New min state save area pointer + */ +#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ + movl _tmp=ia64_os_to_sal_handoff_state;; \ + DATA_VA_TO_PA(_tmp);; \ + ld8 r8=[_tmp],0x08;; \ + ld8 r9=[_tmp],0x08;; \ + ld8 r22=[_tmp],0x08;; + +/* + * BRANCH + * Jump to the instruction referenced by + * "to_label". + * Branch is taken only if the predicate + * register "p" is true. + * "ip" is the address of the instruction + * located at "from_label". + * "temp" is a scratch register like r2 + * "adjust" needed for HP compiler. + * A screwup somewhere with constant arithmetic. + */ +#define BRANCH(to_label, temp, p, adjust) \ +100: (p) mov temp=ip; \ + ;; \ + (p) adds temp=to_label-100b,temp;\ + (p) adds temp=adjust,temp; \ + (p) mov b1=temp ; \ + (p) br b1 + + .global ia64_os_mca_dispatch + .global ia64_os_mca_dispatch_end + .global ia64_sal_to_os_handoff_state + .global ia64_os_to_sal_handoff_state + .global ia64_os_mca_ucmc_handler + .global ia64_mca_proc_state_dump + .global ia64_mca_proc_state_restore + .global ia64_mca_stack + .global ia64_mca_stackframe + .global ia64_mca_bspstore + + .text + .align 16 + +ia64_os_mca_dispatch: + +#if defined(MCA_TEST) + // Pretend that we are in interrupt context + mov r2=psr + dep r2=0, r2, PSR_IC, 2; + mov psr.l = r2 +#endif /* #if defined(MCA_TEST) */ + + // Save the SAL to OS MCA handoff state as defined + // by SAL SPEC 2.5 + // NOTE : The order in which the state gets saved + // is dependent on the way the C-structure + // for ia64_mca_sal_to_os_state_t has been + // defined in include/asm/mca.h + SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) + + // LOG PROCESSOR STATE INFO FROM HERE ON.. + ;; +begin_os_mca_dump: + BRANCH(ia64_os_mca_proc_state_dump, r2, p0, 0x0) + ;; +ia64_os_mca_done_dump: + + // Setup new stack frame for OS_MCA handling + movl r2=ia64_mca_bspstore // local bspstore area location in r2 + movl r3=ia64_mca_stackframe // save stack frame to memory in r3 + rse_switch_context(r6,r3,r2);; // RSC management in this new context + movl r12=ia64_mca_stack;; + + // Enter virtual mode from physical mode + VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4) +ia64_os_mca_virtual_begin: + + // call our handler + movl r2=ia64_mca_ucmc_handler;; + mov b6=r2;; + br.call.sptk.few b0=b6 + ;; + + // Revert back to physical mode before going back to SAL + PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4) +ia64_os_mca_virtual_end: + +#if defined(MCA_TEST) + // Pretend that we are in interrupt context + mov r2=psr + dep r2=0, r2, PSR_IC, 2; + mov psr.l = r2 +#endif /* #if defined(MCA_TEST) */ + + // restore the original stack frame here + movl r2=ia64_mca_stackframe // restore stack frame from memory at r2 + ;; + DATA_VA_TO_PA(r2) + movl r4=IA64_PSR_MC + ;; + rse_return_context(r4,r3,r2) // switch from interrupt context for RSE + + // let us restore all the registers from our PSI structure + mov r8=gp + ;; +begin_os_mca_restore: + BRANCH(ia64_os_mca_proc_state_restore, r2, p0, 0x0) + ;; + +ia64_os_mca_done_restore: + ;; +#ifdef SOFTSDV + VIRTUAL_MODE_ENTER(r2,r3, vmode_enter, r4) +vmode_enter: + br.ret.sptk.few b0 +#else + // branch back to SALE_CHECK + OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2) + ld8 r3=[r2];; + mov b0=r3 // SAL_CHECK return address + br b0 + ;; +#endif /* #ifdef SOFTSDV */ +ia64_os_mca_dispatch_end: +//EndMain////////////////////////////////////////////////////////////////////// + + +//++ +// Name: +// ia64_os_mca_proc_state_dump() +// +// Stub Description: +// +// This stub dumps the processor state during MCHK to a data area +// +//-- + +ia64_os_mca_proc_state_dump: +// Get and save GR0-31 from Proc. Min. State Save Area to SAL PSI + movl r2=ia64_mca_proc_state_dump;; // Os state dump area + +// save ar.NaT + mov r5=ar.unat // ar.unat + +// save banked GRs 16-31 along with NaT bits + bsw.1;; + st8.spill [r2]=r16,8;; + st8.spill [r2]=r17,8;; + st8.spill [r2]=r18,8;; + st8.spill [r2]=r19,8;; + st8.spill [r2]=r20,8;; + st8.spill [r2]=r21,8;; + st8.spill [r2]=r22,8;; + st8.spill [r2]=r23,8;; + st8.spill [r2]=r24,8;; + st8.spill [r2]=r25,8;; + st8.spill [r2]=r26,8;; + st8.spill [r2]=r27,8;; + st8.spill [r2]=r28,8;; + st8.spill [r2]=r29,8;; + st8.spill [r2]=r30,8;; + st8.spill [r2]=r31,8;; + + mov r4=ar.unat;; + st8 [r2]=r4,8 // save User NaT bits for r16-r31 + mov ar.unat=r5 // restore original unat + bsw.0;; + +//save BRs + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r4 + + mov r3=b0 + mov r5=b1 + mov r7=b2;; + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=b3 + mov r5=b4 + mov r7=b5;; + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=b6 + mov r5=b7;; + st8 [r2]=r3,2*8 + st8 [r4]=r5,2*8;; + +cSaveCRs: +// save CRs + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r4 + + mov r3=cr0 // cr.dcr + mov r5=cr1 // cr.itm + mov r7=cr2;; // cr.iva + + st8 [r2]=r3,8*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; // 48 byte rements + + mov r3=cr8;; // cr.pta + st8 [r2]=r3,8*8;; // 64 byte rements + +// if PSR.ic=0, reading interruption registers causes an illegal operation fault + mov r3=psr;; + tbit.nz.unc p2,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test +(p2) st8 [r2]=r0,9*8+160 // increment by 168 byte inc. +begin_skip_intr_regs: + BRANCH(SkipIntrRegs, r9, p2, 0x0) + ;; + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r6 + + mov r3=cr16 // cr.ipsr + mov r5=cr17 // cr.isr + mov r7=r0;; // cr.ida => cr18 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr19 // cr.iip + mov r5=cr20 // cr.idtr + mov r7=cr21;; // cr.iitr + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr22 // cr.iipa + mov r5=cr23 // cr.ifs + mov r7=cr24;; // cr.iim + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=cr25;; // cr.iha + st8 [r2]=r3,160;; // 160 byte rement + +SkipIntrRegs: + st8 [r2]=r0,168 // another 168 byte . + + mov r3=cr66;; // cr.lid + st8 [r2]=r3,40 // 40 byte rement + + mov r3=cr71;; // cr.ivr + st8 [r2]=r3,8 + + mov r3=cr72;; // cr.tpr + st8 [r2]=r3,24 // 24 byte increment + + mov r3=r0;; // cr.eoi => cr75 + st8 [r2]=r3,168 // 168 byte inc. + + mov r3=r0;; // cr.irr0 => cr96 + st8 [r2]=r3,16 // 16 byte inc. + + mov r3=r0;; // cr.irr1 => cr98 + st8 [r2]=r3,16 // 16 byte inc. + + mov r3=r0;; // cr.irr2 => cr100 + st8 [r2]=r3,16 // 16 byte inc + + mov r3=r0;; // cr.irr3 => cr100 + st8 [r2]=r3,16 // 16b inc. + + mov r3=r0;; // cr.itv => cr114 + st8 [r2]=r3,16 // 16 byte inc. + + mov r3=r0;; // cr.pmv => cr116 + st8 [r2]=r3,8 + + mov r3=r0;; // cr.lrr0 => cr117 + st8 [r2]=r3,8 + + mov r3=r0;; // cr.lrr1 => cr118 + st8 [r2]=r3,8 + + mov r3=r0;; // cr.cmcv => cr119 + st8 [r2]=r3,8*10;; + +cSaveARs: +// save ARs + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r6 + + mov r3=ar0 // ar.kro + mov r5=ar1 // ar.kr1 + mov r7=ar2;; // ar.kr2 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=ar3 // ar.kr3 + mov r5=ar4 // ar.kr4 + mov r7=ar5;; // ar.kr5 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=ar6 // ar.kr6 + mov r5=ar7 // ar.kr7 + mov r7=r0;; // ar.kr8 + st8 [r2]=r3,10*8 + st8 [r4]=r5,10*8 + st8 [r6]=r7,10*8;; // rement by 72 bytes + + mov r3=ar16 // ar.rsc + mov ar16=r0 // put RSE in enforced lazy mode + mov r5=ar17 // ar.bsp + mov r7=ar18;; // ar.bspstore + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; + + mov r3=ar19;; // ar.rnat + st8 [r2]=r3,8*13 // increment by 13x8 bytes + + mov r3=ar32;; // ar.ccv + st8 [r2]=r3,8*4 + + mov r3=ar36;; // ar.unat + st8 [r2]=r3,8*4 + + mov r3=ar40;; // ar.fpsr + st8 [r2]=r3,8*4 + + mov r3=ar44;; // ar.itc + st8 [r2]=r3,160 // 160 + + mov r3=ar64;; // ar.pfs + st8 [r2]=r3,8 + + mov r3=ar65;; // ar.lc + st8 [r2]=r3,8 + + mov r3=ar66;; // ar.ec + st8 [r2]=r3 + add r2=8*62,r2 //padding + +// save RRs + mov ar.lc=0x08-1 + movl r4=0x00;; + +cStRR: + mov r3=rr[r4];; + st8 [r2]=r3,8 + add r4=1,r4 + br.cloop.sptk.few cStRR + ;; +end_os_mca_dump: + BRANCH(ia64_os_mca_done_dump, r2, p0, -0x10) + ;; + +//EndStub////////////////////////////////////////////////////////////////////// + + +//++ +// Name: +// ia64_os_mca_proc_state_restore() +// +// Stub Description: +// +// This is a stub to restore the saved processor state during MCHK +// +//-- + +ia64_os_mca_proc_state_restore: + +// Restore bank1 GR16-31 + movl r2=ia64_mca_proc_state_dump // Convert virtual address + ;; // of OS state dump area + DATA_VA_TO_PA(r2) // to physical address + ;; +restore_GRs: // restore bank-1 GRs 16-31 + bsw.1;; + add r3=16*8,r2;; // to get to NaT of GR 16-31 + ld8 r3=[r3];; + mov ar.unat=r3;; // first restore NaT + + ld8.fill r16=[r2],8;; + ld8.fill r17=[r2],8;; + ld8.fill r18=[r2],8;; + ld8.fill r19=[r2],8;; + ld8.fill r20=[r2],8;; + ld8.fill r21=[r2],8;; + ld8.fill r22=[r2],8;; + ld8.fill r23=[r2],8;; + ld8.fill r24=[r2],8;; + ld8.fill r25=[r2],8;; + ld8.fill r26=[r2],8;; + ld8.fill r27=[r2],8;; + ld8.fill r28=[r2],8;; + ld8.fill r29=[r2],8;; + ld8.fill r30=[r2],8;; + ld8.fill r31=[r2],8;; + + ld8 r3=[r2],8;; // increment to skip NaT + bsw.0;; + +restore_BRs: + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov b0=r3 + mov b1=r5 + mov b2=r7;; + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov b3=r3 + mov b4=r5 + mov b5=r7;; + + ld8 r3=[r2],2*8 + ld8 r5=[r4],2*8;; + mov b6=r3 + mov b7=r5;; + +restore_CRs: + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 + + ld8 r3=[r2],8*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; // 48 byte increments + mov cr0=r3 // cr.dcr + mov cr1=r5 // cr.itm + mov cr2=r7;; // cr.iva + + ld8 r3=[r2],8*8;; // 64 byte increments +// mov cr8=r3 // cr.pta + + +// if PSR.ic=1, reading interruption registers causes an illegal operation fault + mov r3=psr;; + tbit.nz.unc p2,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test +(p2) st8 [r2]=r0,9*8+160 // increment by 160 byte inc. + +begin_rskip_intr_regs: + BRANCH(rSkipIntrRegs, r9, p2, 0x0) + ;; + + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr16=r3 // cr.ipsr + mov cr17=r5 // cr.isr is read only +// mov cr18=r7;; // cr.ida + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr19=r3 // cr.iip + mov cr20=r5 // cr.idtr + mov cr21=r7;; // cr.iitr + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov cr22=r3 // cr.iipa + mov cr23=r5 // cr.ifs + mov cr24=r7 // cr.iim + + ld8 r3=[r2],160;; // 160 byte increment + mov cr25=r3 // cr.iha + +rSkipIntrRegs: + ld8 r3=[r2],168;; // another 168 byte inc. + + ld8 r3=[r2],40;; // 40 byte increment + mov cr66=r3 // cr.lid + + ld8 r3=[r2],8;; +// mov cr71=r3 // cr.ivr is read only + ld8 r3=[r2],24;; // 24 byte increment + mov cr72=r3 // cr.tpr + + ld8 r3=[r2],168;; // 168 byte inc. +// mov cr75=r3 // cr.eoi + + ld8 r3=[r2],16;; // 16 byte inc. +// mov cr96=r3 // cr.irr0 is read only + + ld8 r3=[r2],16;; // 16 byte inc. +// mov cr98=r3 // cr.irr1 is read only + + ld8 r3=[r2],16;; // 16 byte inc +// mov cr100=r3 // cr.irr2 is read only + + ld8 r3=[r2],16;; // 16b inc. +// mov cr102=r3 // cr.irr3 is read only + + ld8 r3=[r2],16;; // 16 byte inc. +// mov cr114=r3 // cr.itv + + ld8 r3=[r2],8;; +// mov cr116=r3 // cr.pmv + ld8 r3=[r2],8;; +// mov cr117=r3 // cr.lrr0 + ld8 r3=[r2],8;; +// mov cr118=r3 // cr.lrr1 + ld8 r3=[r2],8*10;; +// mov cr119=r3 // cr.cmcv + +restore_ARs: + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r4 + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov ar0=r3 // ar.kro + mov ar1=r5 // ar.kr1 + mov ar2=r7;; // ar.kr2 + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; + mov ar3=r3 // ar.kr3 + mov ar4=r5 // ar.kr4 + mov ar5=r7;; // ar.kr5 + + ld8 r3=[r2],10*8 + ld8 r5=[r4],10*8 + ld8 r7=[r6],10*8;; + mov ar6=r3 // ar.kr6 + mov ar7=r5 // ar.kr7 +// mov ar8=r6 // ar.kr8 + ;; + + ld8 r3=[r2],3*8 + ld8 r5=[r4],3*8 + ld8 r7=[r6],3*8;; +// mov ar16=r3 // ar.rsc +// mov ar17=r5 // ar.bsp is read only + mov ar16=r0 // make sure that RSE is in enforced lazy mode + mov ar18=r7;; // ar.bspstore + + ld8 r9=[r2],8*13;; + mov ar19=r9 // ar.rnat + + mov ar16=r3 // ar.rsc + ld8 r3=[r2],8*4;; + mov ar32=r3 // ar.ccv + + ld8 r3=[r2],8*4;; + mov ar36=r3 // ar.unat + + ld8 r3=[r2],8*4;; + mov ar40=r3 // ar.fpsr + + ld8 r3=[r2],160;; // 160 +// mov ar44=r3 // ar.itc + + ld8 r3=[r2],8;; + mov ar64=r3 // ar.pfs + + ld8 r3=[r2],8;; + mov ar65=r3 // ar.lc + + ld8 r3=[r2];; + mov ar66=r3 // ar.ec + add r2=8*62,r2;; // padding + +restore_RRs: + mov r5=ar.lc + mov ar.lc=0x08-1 + movl r4=0x00 +cStRRr: + ld8 r3=[r2],8;; +// mov rr[r4]=r3 // what are its access previledges? + add r4=1,r4 + br.cloop.sptk.few cStRRr + ;; + mov ar.lc=r5 + ;; +end_os_mca_restore: + BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20) + ;; +//EndStub////////////////////////////////////////////////////////////////////// diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/pal.S linux/arch/ia64/kernel/pal.S --- v2.3.42/linux/arch/ia64/kernel/pal.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/pal.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,119 @@ +/* + * PAL Firmware support + * IA-64 Processor Programmers Reference Vol 2 + * + * Copyright (C) 1999 Don Dugger + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999 David Mosberger + */ + + .text + .psr abi64 + .psr lsb + .lsb + + .data +pal_entry_point: + data8 ia64_pal_default_handler + .text + +/* + * Set the PAL entry point address. This could be written in C code, but we do it here + * to keep it all in one module (besides, it's so trivial that it's + * not a big deal). + * + * in0 Address of the PAL entry point (text address, NOT a function descriptor). + */ + .align 16 + .global ia64_pal_handler_init + .proc ia64_pal_handler_init +ia64_pal_handler_init: + alloc r3=ar.pfs,1,0,0,0 + movl r2=pal_entry_point + ;; + st8 [r2]=in0 + br.ret.sptk.few rp + + .endp ia64_pal_handler_init + +/* + * Default PAL call handler. This needs to be coded in assembly because it uses + * the static calling convention, i.e., the RSE may not be used and calls are + * done via "br.cond" (not "br.call"). + */ + .align 16 + .global ia64_pal_default_handler + .proc ia64_pal_default_handler +ia64_pal_default_handler: + mov r8=-1 + br.cond.sptk.few rp + +/* + * Make a PAL call using the static calling convention. + * + * in0 Pointer to struct ia64_pal_retval + * in1 Index of PAL service + * in2 - in4 Remaning PAL arguments + * + */ + +#ifdef __GCC_MULTIREG_RETVALS__ +# define arg0 in0 +# define arg1 in1 +# define arg2 in2 +# define arg3 in3 +# define arg4 in4 +#else +# define arg0 in1 +# define arg1 in2 +# define arg2 in3 +# define arg3 in4 +# define arg4 in5 +#endif + + .text + .psr abi64 + .psr lsb + .lsb + + .align 16 + .global ia64_pal_call_static + .proc ia64_pal_call_static +ia64_pal_call_static: + alloc loc0 = ar.pfs,6,90,0,0 + movl loc2 = pal_entry_point +1: { + mov r28 = arg0 + mov r29 = arg1 + mov r8 = ip + } + ;; + ld8 loc2 = [loc2] // loc2 <- entry point + mov r30 = arg2 + mov r31 = arg3 + ;; + mov loc3 = psr + mov loc1 = rp + adds r8 = .ret0-1b,r8 + ;; + rsm psr.i + mov b7 = loc2 + mov rp = r8 + ;; + br.cond.sptk.few b7 +.ret0: mov psr.l = loc3 +#ifndef __GCC_MULTIREG_RETVALS__ + st8 [in0] = r8, 8 + ;; + st8 [in0] = r9, 8 + ;; + st8 [in0] = r10, 8 + ;; + st8 [in0] = r11, 8 +#endif + mov ar.pfs = loc0 + mov rp = loc1 + ;; + srlz.d // seralize restoration of psr.l + br.ret.sptk.few b0 + .endp ia64_pal_call_static diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/pci-dma.c linux/arch/ia64/kernel/pci-dma.c --- v2.3.42/linux/arch/ia64/kernel/pci-dma.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/pci-dma.c Wed Feb 9 19:45:43 2000 @@ -0,0 +1,56 @@ +/* + * Dynamic DMA mapping support. + * + * This implementation is for IA-64 platforms that do not support + * I/O TLBs (aka DMA address translation hardware). + * + * XXX This doesn't do the right thing yet. It appears we would have + * to add additional zones so we can implement the various address + * mask constraints that we might encounter. A zone for memory < 32 + * bits is obviously necessary... + */ + +#include +#include +#include +#include + +#include + +/* Pure 2^n version of get_order */ +extern __inline__ unsigned long +get_order (unsigned long size) +{ + unsigned long order = ia64_fls(size); + + printk ("get_order: size=%lu, order=%lu\n", size, order); + + if (order > PAGE_SHIFT) + order -= PAGE_SHIFT; + else + order = 0; + return order; +} + +void * +pci_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + + if (!hwdev || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} + +void +pci_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long) vaddr, get_order(size)); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c --- v2.3.42/linux/arch/ia64/kernel/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/pci.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,239 @@ +/* + * pci.c - Low-Level PCI Access in IA64 + * + * Derived from bios32.c of i386 tree. + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +#ifdef CONFIG_SMP +# include +#endif +#include + + +#undef DEBUG +#define DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +/* + * This interrupt-safe spinlock protects all accesses to PCI + * configuration space. + */ + +spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; + +struct pci_fixup pcibios_fixups[] = { { 0 } }; + +#define PCI_NO_CHECKS 0x400 +#define PCI_NO_PEER_FIXUP 0x800 + +static unsigned int pci_probe = PCI_NO_CHECKS; + +/* Macro to build a PCI configuration address to be passed as a parameter to SAL. */ + +#define PCI_CONFIG_ADDRESS(dev, where) (((u64) dev->bus->number << 16) | ((u64) (dev->devfn & 0xff) << 8) | (where & 0xff)) + +static int +pci_conf_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + s64 status; + u64 lval; + + status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 1, &lval); + *value = lval; + return status; +} + +static int +pci_conf_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + s64 status; + u64 lval; + + status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 2, &lval); + *value = lval; + return status; +} + +static int +pci_conf_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + s64 status; + u64 lval; + + status = ia64_sal_pci_config_read(PCI_CONFIG_ADDRESS(dev, where), 4, &lval); + *value = lval; + return status; +} + +static int +pci_conf_write_config_byte (struct pci_dev *dev, int where, u8 value) +{ + return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 1, value); +} + +static int +pci_conf_write_config_word (struct pci_dev *dev, int where, u16 value) +{ + return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 2, value); +} + +static int +pci_conf_write_config_dword (struct pci_dev *dev, int where, u32 value) +{ + return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 4, value); +} + + +static struct pci_ops pci_conf = { + pci_conf_read_config_byte, + pci_conf_read_config_word, + pci_conf_read_config_dword, + pci_conf_write_config_byte, + pci_conf_write_config_word, + pci_conf_write_config_dword +}; + +/* + * Try to find PCI BIOS. This will always work for IA64. + */ + +static struct pci_ops * __init +pci_find_bios(void) +{ + return &pci_conf; +} + +/* + * Initialization. Uses the SAL interface + */ + +#define PCI_BUSSES_TO_SCAN 2 /* On "real" ;) hardware this will be 255 */ + +void __init +pcibios_init(void) +{ + struct pci_ops *ops = NULL; + int i; + + if ((ops = pci_find_bios()) == NULL) { + printk("PCI: No PCI bus detected\n"); + return; + } + + printk("PCI: Probing PCI hardware\n"); + for (i = 0; i < PCI_BUSSES_TO_SCAN; i++) + pci_scan_bus(i, ops, NULL); + platform_pci_fixup(); + return; +} + +/* + * Called after each bus is probed, but before its children + * are examined. + */ + +void __init +pcibios_fixup_bus(struct pci_bus *b) +{ + return; +} + +int +pci_assign_resource (struct pci_dev *dev, int i) +{ + printk("pci_assign_resource: not implemented!\n"); + return -ENODEV; +} + +void __init +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + unsigned long where, size; + u32 reg; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); + + /* ??? FIXME -- record old value for shutdown. */ +} + +void __init +pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); + + /* ??? FIXME -- record old value for shutdown. */ +} + +void __init +pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + +int __init +pcibios_enable_device (struct pci_dev *dev) +{ + /* Not needed, since we enable all devices at startup. */ + return 0; +} + +/* + * PCI BIOS setup, always defaults to SAL interface + */ + +char * __init +pcibios_setup(char *str) +{ + pci_probe = PCI_NO_CHECKS; + return NULL; +} + +void +pcibios_align_resource (void *data, struct resource *res, unsigned long size) +{ +} + +#if 0 /*def CONFIG_PROC_FS*/ +/* + * This is an ugly hack to get a (weak) unresolved reference to something that is + * in drivers/pci/proc.c. Without this, the file does not get linked in at all + * (I suspect the reason this isn't needed on Linux/x86 is that most people compile + * with module support, in which case the EXPORT_SYMBOL() stuff will ensure the + * code gets linked in. Sigh... --davidm 99/12/20. + */ +asm ("data8 proc_bus_pci_add"); +#endif diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c --- v2.3.42/linux/arch/ia64/kernel/perfmon.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/perfmon.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,227 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PERFMON + +#define MAX_PERF_COUNTER 4 /* true for Itanium, at least */ +#define WRITE_PMCS_AND_START 0xa0 +#define WRITE_PMCS 0xa1 +#define READ_PMDS 0xa2 +#define STOP_PMCS 0xa3 +#define IA64_COUNTER_MASK 0xffffffffffffff6f +#define PERF_OVFL_VAL 0xffffffff + +struct perfmon_counter { + unsigned long data; + int counter_num; +}; + +unsigned long pmds[MAX_PERF_COUNTER]; +struct task_struct *perf_owner; + +/* + * We set dcr.pp, psr.pp, and the appropriate pmc control values with + * this. Notice that we go about modifying _each_ task's pt_regs to + * set cr_ipsr.pp. This will start counting when "current" does an + * _rfi_. Also, since each task's cr_ipsr.pp, and cr_ipsr is inherited + * across forks, we do _not_ need additional code on context + * switches. On stopping of the counters we dont _need_ to go about + * changing every task's cr_ipsr back to where it wuz, because we can + * just set pmc[0]=1. But we do it anyways becuase we will probably + * add thread specific accounting later. + * + * The obvious problem with this is that on SMP systems, it is a bit + * of work (when someone wants to do it) - it would be easier if we + * just added code to the context-switch path. I think we would need + * to lock the run queue to ensure no context switches, send an IPI to + * each processor, and in that IPI handler, just modify the psr bit of + * only the _current_ thread, since we have modified the psr bit + * correctly in the kernel stack for every process which is not + * running. Might crash on SMP systems without the + * lock_kernel(). Hence the lock.. + */ +asmlinkage unsigned long +sys_perfmonctl (int cmd1, int cmd2, void *ptr) +{ + struct perfmon_counter tmp, *cptr = ptr; + unsigned long pmd, cnum, dcr, flags; + struct task_struct *p; + struct pt_regs *regs; + struct perf_counter; + int i; + + switch (cmd1) { + case WRITE_PMCS: /* Writes to PMC's and clears PMDs */ + case WRITE_PMCS_AND_START: /* Also starts counting */ + + if (!access_ok(VERIFY_READ, cptr, sizeof(struct perf_counter)*cmd2)) + return -EFAULT; + + if (cmd2 >= MAX_PERF_COUNTER) + return -EFAULT; + + if (perf_owner && perf_owner != current) + return -EBUSY; + perf_owner = current; + + for (i = 0; i < cmd2; i++, cptr++) { + copy_from_user(&tmp, cptr, sizeof(tmp)); + /* XXX need to check validity of counter_num and perhaps data!! */ + ia64_set_pmc(tmp.counter_num, tmp.data); + ia64_set_pmd(tmp.counter_num, 0); + pmds[tmp.counter_num - 4] = 0; + } + + if (cmd1 == WRITE_PMCS_AND_START) { + local_irq_save(flags); + dcr = ia64_get_dcr(); + dcr |= IA64_DCR_PP; + ia64_set_dcr(dcr); + local_irq_restore(flags); + + /* + * This is a no can do. It obviously wouldn't + * work on SMP where another process may not + * be blocked at all. + * + * Perhaps we need a global predicate in the + * leave_kernel path to control if pp should + * be on or off? + */ + lock_kernel(); + for_each_task(p) { + regs = (struct pt_regs *) (((char *)p) + IA64_STK_OFFSET) - 1; + ia64_psr(regs)->pp = 1; + } + unlock_kernel(); + ia64_set_pmc(0, 0); + } + break; + + case READ_PMDS: + if (cmd2 >= MAX_PERF_COUNTER) + return -EFAULT; + if (!access_ok(VERIFY_WRITE, cptr, sizeof(struct perf_counter)*cmd2)) + return -EFAULT; + local_irq_save(flags); + /* XXX this looks wrong */ + __asm__ __volatile__("rsm psr.pp\n"); + dcr = ia64_get_dcr(); + dcr &= ~IA64_DCR_PP; + ia64_set_dcr(dcr); + local_irq_restore(flags); + + /* + * We cannot touch pmc[0] to stop counting here, as + * that particular instruction might cause an overflow + * and the mask in pmc[0] might get lost. I'm not very + * sure of the hardware behavior here. So we stop + * counting by psr.pp = 0. And we reset dcr.pp to + * prevent an interrupt from mucking up psr.pp in the + * meanwhile. Perfmon interrupts are pended, hence the + * above code should be ok if one of the above + * instructions cause overflows. Is this ok? When I + * muck with dcr, is the cli/sti needed?? + */ + for (i = 0, cnum = 4; i < MAX_PERF_COUNTER; i++, cnum++, cptr++) { + pmd = pmds[i] + (ia64_get_pmd(cnum) & PERF_OVFL_VAL); + put_user(pmd, &cptr->data); + } + local_irq_save(flags); + /* XXX this looks wrong */ + __asm__ __volatile__("ssm psr.pp"); + dcr = ia64_get_dcr(); + dcr |= IA64_DCR_PP; + ia64_set_dcr(dcr); + local_irq_restore(flags); + break; + + case STOP_PMCS: + ia64_set_pmc(0, 1); + for (i = 0; i < MAX_PERF_COUNTER; ++i) + ia64_set_pmc(i, 0); + + local_irq_save(flags); + dcr = ia64_get_dcr(); + dcr &= ~IA64_DCR_PP; + ia64_set_dcr(dcr); + local_irq_restore(flags); + /* + * This is a no can do. It obviously wouldn't + * work on SMP where another process may not + * be blocked at all. + * + * Perhaps we need a global predicate in the + * leave_kernel path to control if pp should + * be on or off? + */ + lock_kernel(); + for_each_task(p) { + regs = (struct pt_regs *) (((char *)p) + IA64_STK_OFFSET) - 1; + ia64_psr(regs)->pp = 0; + } + unlock_kernel(); + perf_owner = 0; + break; + + default: + break; + } + return 0; +} + +static inline void +update_counters (void) +{ + unsigned long mask, i, cnum, val; + + mask = ia64_get_pmd(0) >> 4; + for (i = 0, cnum = 4; i < MAX_PERF_COUNTER; cnum++, i++, mask >>= 1) { + if (mask & 0x1) + val = PERF_OVFL_VAL; + else + /* since we got an interrupt, might as well clear every pmd. */ + val = ia64_get_pmd(cnum) & PERF_OVFL_VAL; + pmds[i] += val; + ia64_set_pmd(cnum, 0); + } +} + +static void +perfmon_interrupt (int irq, void *arg, struct pt_regs *regs) +{ + update_counters(); + ia64_set_pmc(0, 0); + ia64_srlz_d(); +} + +void +perfmon_init (void) +{ + if (request_irq(PERFMON_IRQ, perfmon_interrupt, 0, "perfmon", NULL)) { + printk("perfmon_init: could not allocate performance monitor vector %u\n", + PERFMON_IRQ); + return; + } + ia64_set_pmv(PERFMON_IRQ); + ia64_srlz_d(); +} + +#else /* !CONFIG_PERFMON */ + +asmlinkage unsigned long +sys_perfmonctl (int cmd1, int cmd2, void *ptr) +{ + return -ENOSYS; +} + +#endif /* !CONFIG_PERFMON */ diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c --- v2.3.42/linux/arch/ia64/kernel/process.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/process.c Tue Feb 8 11:32:18 2000 @@ -0,0 +1,421 @@ +/* + * Architecture-specific setup. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + */ +#define __KERNEL_SYSCALLS__ /* see */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +void +show_regs (struct pt_regs *regs) +{ + unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri; + + printk("\npsr : %016lx ifs : %016lx ip : [<%016lx>]\n", + regs->cr_ipsr, regs->cr_ifs, ip); + printk("unat: %016lx pfs : %016lx rsc : %016lx\n", + regs->ar_unat, regs->ar_pfs, regs->ar_rsc); + printk("rnat: %016lx bsps: %016lx pr : %016lx\n", + regs->ar_rnat, regs->ar_bspstore, regs->pr); + printk("ldrs: %016lx ccv : %016lx fpsr: %016lx\n", + regs->loadrs, regs->ar_ccv, regs->ar_fpsr); + printk("b0 : %016lx b6 : %016lx b7 : %016lx\n", regs->b0, regs->b6, regs->b7); + printk("f6 : %05lx%016lx f7 : %05lx%016lx\n", + regs->f6.u.bits[1], regs->f6.u.bits[0], + regs->f7.u.bits[1], regs->f7.u.bits[0]); + printk("f8 : %05lx%016lx f9 : %05lx%016lx\n", + regs->f8.u.bits[1], regs->f8.u.bits[0], + regs->f9.u.bits[1], regs->f9.u.bits[0]); + + printk("r1 : %016lx r2 : %016lx r3 : %016lx\n", regs->r1, regs->r2, regs->r3); + printk("r8 : %016lx r9 : %016lx r10 : %016lx\n", regs->r8, regs->r9, regs->r10); + printk("r11 : %016lx r12 : %016lx r13 : %016lx\n", regs->r11, regs->r12, regs->r13); + printk("r14 : %016lx r15 : %016lx r16 : %016lx\n", regs->r14, regs->r15, regs->r16); + printk("r17 : %016lx r18 : %016lx r19 : %016lx\n", regs->r17, regs->r18, regs->r19); + printk("r20 : %016lx r21 : %016lx r22 : %016lx\n", regs->r20, regs->r21, regs->r22); + printk("r23 : %016lx r24 : %016lx r25 : %016lx\n", regs->r23, regs->r24, regs->r25); + printk("r26 : %016lx r27 : %016lx r28 : %016lx\n", regs->r26, regs->r27, regs->r28); + printk("r29 : %016lx r30 : %016lx r31 : %016lx\n", regs->r29, regs->r30, regs->r31); + + /* print the stacked registers if cr.ifs is valid: */ + if (regs->cr_ifs & 0x8000000000000000) { + unsigned long val, sof, *bsp, ndirty; + int i, is_nat = 0; + + sof = regs->cr_ifs & 0x7f; /* size of frame */ + ndirty = (regs->loadrs >> 19); + bsp = ia64_rse_skip_regs((unsigned long *) regs->ar_bspstore, ndirty); + for (i = 0; i < sof; ++i) { + get_user(val, ia64_rse_skip_regs(bsp, i)); + printk("r%-3u:%c%016lx%s", 32 + i, is_nat ? '*' : ' ', val, + ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); + } + } +} + +void __attribute__((noreturn)) +cpu_idle (void *unused) +{ + /* endless idle loop with no priority at all */ + init_idle(); + current->priority = 0; + current->counter = -100; + +#ifdef CONFIG_SMP + if (!current->need_resched) + min_xtp(); +#endif + + while (1) { + while (!current->need_resched) { + continue; + } +#ifdef CONFIG_SMP + normal_xtp(); +#endif + schedule(); + check_pgt_cache(); + if (pm_idle) + (*pm_idle)(); + } +} + +/* + * Copy the state of an ia-64 thread. + * + * We get here through the following call chain: + * + * + * sys_clone + * do_fork + * copy_thread + * + * This means that the stack layout is as follows: + * + * +---------------------+ (highest addr) + * | struct pt_regs | + * +---------------------+ + * | struct switch_stack | + * +---------------------+ + * | | + * | memory stack | + * | | <-- sp (lowest addr) + * +---------------------+ + * + * Note: if we get called through kernel_thread() then the memory + * above "(highest addr)" is valid kernel stack memory that needs to + * be copied as well. + * + * Observe that we copy the unat values that are in pt_regs and + * switch_stack. Since the interpretation of unat is dependent upon + * the address to which the registers got spilled, doing this is valid + * only as long as we preserve the alignment of the stack. Since the + * stack is always page aligned, we know this is the case. + * + * XXX Actually, the above isn't true when we create kernel_threads(). + * If we ever needs to create kernel_threads() that preserve the unat + * values we'll need to fix this. Perhaps an easy workaround would be + * to always clear the unat bits in the child thread. + */ +int +copy_thread (int nr, unsigned long clone_flags, unsigned long usp, + struct task_struct *p, struct pt_regs *regs) +{ + unsigned long rbs, child_rbs, rbs_size, stack_offset, stack_top, stack_used; + struct switch_stack *child_stack, *stack; + extern char ia64_ret_from_syscall_clear_r8; + extern char ia64_strace_clear_r8; + struct pt_regs *child_ptregs; + +#ifdef CONFIG_SMP + /* + * For SMP idle threads, fork_by_hand() calls do_fork with + * NULL regs. + */ + if (!regs) + return 0; +#endif + + stack_top = (unsigned long) current + IA64_STK_OFFSET; + stack = ((struct switch_stack *) regs) - 1; + stack_used = stack_top - (unsigned long) stack; + stack_offset = IA64_STK_OFFSET - stack_used; + + child_stack = (struct switch_stack *) ((unsigned long) p + stack_offset); + child_ptregs = (struct pt_regs *) (child_stack + 1); + + /* copy parent's switch_stack & pt_regs to child: */ + memcpy(child_stack, stack, stack_used); + + rbs = (unsigned long) current + IA64_RBS_OFFSET; + child_rbs = (unsigned long) p + IA64_RBS_OFFSET; + rbs_size = stack->ar_bspstore - rbs; + + /* copy the parent's register backing store to the child: */ + memcpy((void *) child_rbs, (void *) rbs, rbs_size); + + child_ptregs->r8 = 0; /* child gets a zero return value */ + if (user_mode(child_ptregs)) + child_ptregs->r12 = usp; /* user stack pointer */ + else { + /* + * Note: we simply preserve the relative position of + * the stack pointer here. There is no need to + * allocate a scratch area here, since that will have + * been taken care of by the caller of sys_clone() + * already. + */ + child_ptregs->r12 = (unsigned long) (child_ptregs + 1); /* kernel sp */ + child_ptregs->r13 = (unsigned long) p; /* set `current' pointer */ + } + if (p->flags & PF_TRACESYS) + child_stack->b0 = (unsigned long) &ia64_strace_clear_r8; + else + child_stack->b0 = (unsigned long) &ia64_ret_from_syscall_clear_r8; + child_stack->ar_bspstore = child_rbs + rbs_size; + + /* copy the thread_struct: */ + p->thread.ksp = (unsigned long) child_stack - 16; + /* + * NOTE: The calling convention considers all floating point + * registers in the high partition (fph) to be scratch. Since + * the only way to get to this point is through a system call, + * we know that the values in fph are all dead. Hence, there + * is no need to inherit the fph state from the parent to the + * child and all we have to do is to make sure that + * IA64_THREAD_FPH_VALID is cleared in the child. + * + * XXX We could push this optimization a bit further by + * clearing IA64_THREAD_FPH_VALID on ANY system call. + * However, it's not clear this is worth doing. Also, it + * would be a slight deviation from the normal Linux system + * call behavior where scratch registers are preserved across + * system calls (unless used by the system call itself). + * + * If we wanted to inherit the fph state from the parent to the + * child, we would have to do something along the lines of: + * + * if (ia64_get_fpu_owner() == current && ia64_psr(regs)->mfh) { + * p->thread.flags |= IA64_THREAD_FPH_VALID; + * ia64_save_fpu(&p->thread.fph); + * } else if (current->thread.flags & IA64_THREAD_FPH_VALID) { + * memcpy(p->thread.fph, current->thread.fph, sizeof(p->thread.fph)); + * } + */ + p->thread.flags = (current->thread.flags & ~IA64_THREAD_FPH_VALID); + return 0; +} + +void +ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst) +{ + struct switch_stack *sw = ((struct switch_stack *) pt) - 1; + unsigned long ar_ec, cfm, ar_bsp, ndirty, *krbs; + + ar_ec = (sw->ar_pfs >> 52) & 0x3f; + + cfm = pt->cr_ifs & ((1UL << 63) - 1); + if ((pt->cr_ifs & (1UL << 63)) == 0) { + /* if cr_ifs isn't valid, we got here through a syscall or a break */ + cfm = sw->ar_pfs & ((1UL << 38) - 1); + } + + krbs = (unsigned long *) current + IA64_RBS_OFFSET/8; + ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 16)); + ar_bsp = (long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty); + + /* r0-r31 + * NaT bits (for r0-r31; bit N == 1 iff rN is a NaT) + * predicate registers (p0-p63) + * b0-b7 + * ip cfm user-mask + * ar.rsc ar.bsp ar.bspstore ar.rnat + * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec + */ + memset(dst, 0, sizeof (dst)); /* don't leak any "random" bits */ + + /* r0 is zero */ dst[ 1] = pt->r1; dst[ 2] = pt->r2; dst[ 3] = pt->r3; + dst[ 4] = sw->r4; dst[ 5] = sw->r5; dst[ 6] = sw->r6; dst[ 7] = sw->r7; + dst[ 8] = pt->r8; dst[ 9] = pt->r9; dst[10] = pt->r10; dst[11] = pt->r11; + dst[12] = pt->r12; dst[13] = pt->r13; dst[14] = pt->r14; dst[15] = pt->r15; + memcpy(dst + 16, &pt->r16, 16*8); /* r16-r31 are contiguous */ + + dst[32] = ia64_get_nat_bits(pt, sw); + dst[33] = pt->pr; + + /* branch regs: */ + dst[34] = pt->b0; dst[35] = sw->b1; dst[36] = sw->b2; dst[37] = sw->b3; + dst[38] = sw->b4; dst[39] = sw->b5; dst[40] = pt->b6; dst[41] = pt->b7; + + dst[42] = pt->cr_iip; dst[43] = pt->cr_ifs; + dst[44] = pt->cr_ipsr; /* XXX perhaps we should filter out some bits here? --davidm */ + + dst[45] = pt->ar_rsc; dst[46] = ar_bsp; dst[47] = pt->ar_bspstore; dst[48] = pt->ar_rnat; + dst[49] = pt->ar_ccv; dst[50] = pt->ar_unat; dst[51] = sw->ar_fpsr; dst[52] = pt->ar_pfs; + dst[53] = sw->ar_lc; dst[54] = (sw->ar_pfs >> 52) & 0x3f; +} + +int +dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) +{ + struct switch_stack *sw = ((struct switch_stack *) pt) - 1; + struct task_struct *fpu_owner = ia64_get_fpu_owner(); + + memset(dst, 0, sizeof (dst)); /* don't leak any "random" bits */ + + /* f0 is 0.0 */ /* f1 is 1.0 */ dst[2] = sw->f2; dst[3] = sw->f3; + dst[4] = sw->f4; dst[5] = sw->f5; dst[6] = pt->f6; dst[7] = pt->f7; + dst[8] = pt->f8; dst[9] = pt->f9; + memcpy(dst + 10, &sw->f10, 22*16); /* f10-f31 are contiguous */ + + if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) { + if (fpu_owner == current) { + __ia64_save_fpu(current->thread.fph); + } + memcpy(dst + 32, current->thread.fph, 96*16); + } + return 1; /* f0-f31 are always valid so we always return 1 */ +} + +asmlinkage long +sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs) +{ + int error; + + lock_kernel(); + filename = getname(filename); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); +out: + unlock_kernel(); + return error; +} + +pid_t +kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) +{ + struct task_struct *parent = current; + int result; + + clone(flags | CLONE_VM, 0); + if (parent != current) { + result = (*fn)(arg); + _exit(result); + } + return 0; /* parent: just return */ +} + +/* + * Flush thread state. This is called when a thread does an execve(). + */ +void +flush_thread (void) +{ + /* drop floating-point and debug-register state if it exists: */ + current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID); + + if (ia64_get_fpu_owner() == current) { + ia64_set_fpu_owner(0); + } +} + +/* + * Clean up state associated with current thread. This is called when + * the thread calls exit(). + */ +void +exit_thread (void) +{ + if (ia64_get_fpu_owner() == current) { + ia64_set_fpu_owner(0); + } +} + +/* + * Free remaining state associated with DEAD_TASK. This is called + * after the parent of DEAD_TASK has collected the exist status of the + * task via wait(). + */ +void +release_thread (struct task_struct *dead_task) +{ + /* nothing to do */ +} + +unsigned long +get_wchan (struct task_struct *p) +{ + struct ia64_frame_info info; + unsigned long ip; + int count = 0; + /* + * These bracket the sleeping functions.. + */ + extern void scheduling_functions_start_here(void); + extern void scheduling_functions_end_here(void); +# define first_sched ((unsigned long) scheduling_functions_start_here) +# define last_sched ((unsigned long) scheduling_functions_end_here) + + /* + * Note: p may not be a blocked task (it could be current or + * another process running on some other CPU. Rather than + * trying to determine if p is really blocked, we just assume + * it's blocked and rely on the unwind routines to fail + * gracefully if the process wasn't really blocked after all. + * --davidm 99/12/15 + */ + ia64_unwind_init_from_blocked_task(&info, p); + do { + if (ia64_unwind_to_previous_frame(&info) < 0) + return 0; + ip = ia64_unwind_get_ip(&info); + if (ip < first_sched || ip >= last_sched) + return ip; + } while (count++ < 16); + return 0; +# undef first_sched +# undef last_sched +} + +void +machine_restart (char *restart_cmd) +{ + (*efi.reset_system)(EFI_RESET_WARM, 0, 0, 0); +} + +void +machine_halt (void) +{ + printk("machine_halt: need PAL or ACPI version here!!\n"); + machine_restart(0); +} + +void +machine_power_off (void) +{ + printk("machine_power_off: unimplemented (need ACPI version here)\n"); + machine_halt (); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.3.42/linux/arch/ia64/kernel/ptrace.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/ptrace.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,653 @@ +/* + * Kernel support for the ptrace() and syscall tracing interfaces. + * + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang + * + * Derived from the x86 and Alpha versions. Most of the code in here + * could actually be factored into a common set of routines. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * Collect the NaT bits for r1-r31 from sw->caller_unat and + * sw->ar_unat and return a NaT bitset where bit i is set iff the NaT + * bit of register i is set. + */ +long +ia64_get_nat_bits (struct pt_regs *pt, struct switch_stack *sw) +{ +# define GET_BITS(str, first, last, unat) \ + ({ \ + unsigned long bit = ia64_unat_pos(&str->r##first); \ + unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \ + (ia64_rotl(unat, first) >> bit) & mask; \ + }) + unsigned long val; + + val = GET_BITS(pt, 1, 3, sw->caller_unat); + val |= GET_BITS(pt, 12, 15, sw->caller_unat); + val |= GET_BITS(pt, 8, 11, sw->caller_unat); + val |= GET_BITS(pt, 16, 31, sw->caller_unat); + val |= GET_BITS(sw, 4, 7, sw->ar_unat); + return val; + +# undef GET_BITS +} + +/* + * Store the NaT bitset NAT in pt->caller_unat and sw->ar_unat. + */ +void +ia64_put_nat_bits (struct pt_regs *pt, struct switch_stack *sw, unsigned long nat) +{ +# define PUT_BITS(str, first, last, nat) \ + ({ \ + unsigned long bit = ia64_unat_pos(&str->r##first); \ + unsigned long mask = ((1UL << (last - first + 1)) - 1) << bit; \ + (ia64_rotr(nat, first) << bit) & mask; \ + }) + sw->caller_unat = PUT_BITS(pt, 1, 3, nat); + sw->caller_unat |= PUT_BITS(pt, 12, 15, nat); + sw->caller_unat |= PUT_BITS(pt, 8, 11, nat); + sw->caller_unat |= PUT_BITS(pt, 16, 31, nat); + sw->ar_unat = PUT_BITS(sw, 4, 7, nat); + +# undef PUT_BITS +} + +#define IA64_MLI_TEMPLATE 0x2 +#define IA64_MOVL_OPCODE 6 + +void +ia64_increment_ip (struct pt_regs *regs) +{ + unsigned long w0, w1, ri = ia64_psr(regs)->ri + 1; + + if (ri > 2) { + ri = 0; + regs->cr_iip += 16; + } else if (ri == 2) { + get_user(w0, (char *) regs->cr_iip + 0); + get_user(w1, (char *) regs->cr_iip + 8); + if (((w0 >> 1) & 0xf) == IA64_MLI_TEMPLATE && (w1 >> 60) == IA64_MOVL_OPCODE) { + /* + * rfi'ing to slot 2 of an MLI bundle causes + * an illegal operation fault. We don't want + * that to happen... Note that we check the + * opcode only. "movl" has a vc bit of 0, but + * since a vc bit of 1 is currently reserved, + * we might just as well treat it like a movl. + */ + ri = 0; + regs->cr_iip += 16; + } + } + ia64_psr(regs)->ri = ri; +} + +void +ia64_decrement_ip (struct pt_regs *regs) +{ + unsigned long w0, w1, ri = ia64_psr(regs)->ri - 1; + + if (ia64_psr(regs)->ri == 0) { + regs->cr_iip -= 16; + ri = 2; + get_user(w0, (char *) regs->cr_iip + 0); + get_user(w1, (char *) regs->cr_iip + 8); + if (((w0 >> 1) & 0xf) == IA64_MLI_TEMPLATE && (w1 >> 60) == IA64_MOVL_OPCODE) { + /* + * rfi'ing to slot 2 of an MLI bundle causes + * an illegal operation fault. We don't want + * that to happen... Note that we check the + * opcode only. "movl" has a vc bit of 0, but + * since a vc bit of 1 is currently reserved, + * we might just as well treat it like a movl. + */ + ri = 1; + } + } + ia64_psr(regs)->ri = ri; +} + +/* + * This routine is used to read an rnat bits that are stored on the + * kernel backing store. Since, in general, the alignment of the user + * and kernel are different, this is not completely trivial. In + * essence, we need to construct the user RNAT based on up to two + * kernel RNAT values and/or the RNAT value saved in the child's + * pt_regs. + * + * user rbs + * + * +--------+ <-- lowest address + * | slot62 | + * +--------+ + * | rnat | 0x....1f8 + * +--------+ + * | slot00 | \ + * +--------+ | + * | slot01 | > child_regs->ar_rnat + * +--------+ | + * | slot02 | / kernel rbs + * +--------+ +--------+ + * <- child_regs->ar_bspstore | slot61 | <-- krbs + * +- - - - + +--------+ + * | slot62 | + * +- - - - + +--------+ + * | rnat | + * +- - - - + +--------+ + * vrnat | slot00 | + * +- - - - + +--------+ + * = = + * +--------+ + * | slot00 | \ + * +--------+ | + * | slot01 | > child_stack->ar_rnat + * +--------+ | + * | slot02 | / + * +--------+ + * <--- child_stack->ar_bspstore + * + * The way to think of this code is as follows: bit 0 in the user rnat + * corresponds to some bit N (0 <= N <= 62) in one of the kernel rnat + * value. The kernel rnat value holding this bit is stored in + * variable rnat0. rnat1 is loaded with the kernel rnat value that + * form the upper bits of the user rnat value. + * + * Boundary cases: + * + * o when reading the rnat "below" the first rnat slot on the kernel + * backing store, rnat0/rnat1 are set to 0 and the low order bits + * are merged in from pt->ar_rnat. + * + * o when reading the rnat "above" the last rnat slot on the kernel + * backing store, rnat0/rnat1 gets its value from sw->ar_rnat. + */ +static unsigned long +get_rnat (struct pt_regs *pt, struct switch_stack *sw, + unsigned long *krbs, unsigned long *urnat_addr) +{ + unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, kmask = ~0UL; + unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; + long num_regs; + + kbsp = (unsigned long *) sw->ar_bspstore; + ubspstore = (unsigned long *) pt->ar_bspstore; + /* + * First, figure out which bit number slot 0 in user-land maps + * to in the kernel rnat. Do this by figuring out how many + * register slots we're beyond the user's backingstore and + * then computing the equivalent address in kernel space. + */ + num_regs = ia64_rse_num_regs(ubspstore, urnat_addr + 1); + slot0_kaddr = ia64_rse_skip_regs(krbs, num_regs); + shift = ia64_rse_slot_num(slot0_kaddr); + rnat1_kaddr = ia64_rse_rnat_addr(slot0_kaddr); + rnat0_kaddr = rnat1_kaddr - 64; + + if (ubspstore + 63 > urnat_addr) { + /* some bits need to be merged in from pt->ar_rnat */ + kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1); + urnat = (pt->ar_rnat & ~kmask); + } + if (rnat0_kaddr >= kbsp) { + rnat0 = sw->ar_rnat; + } else if (rnat0_kaddr > krbs) { + rnat0 = *rnat0_kaddr; + } + if (rnat1_kaddr >= kbsp) { + rnat1 = sw->ar_rnat; + } else if (rnat1_kaddr > krbs) { + rnat1 = *rnat1_kaddr; + } + urnat |= ((rnat1 << (63 - shift)) | (rnat0 >> shift)) & kmask; + return urnat; +} + +/* + * The reverse of get_rnat. + */ +static void +put_rnat (struct pt_regs *pt, struct switch_stack *sw, + unsigned long *krbs, unsigned long *urnat_addr, unsigned long urnat) +{ + unsigned long rnat0 = 0, rnat1 = 0, rnat = 0, *slot0_kaddr, kmask = ~0UL, mask; + unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; + long num_regs; + + kbsp = (unsigned long *) sw->ar_bspstore; + ubspstore = (unsigned long *) pt->ar_bspstore; + /* + * First, figure out which bit number slot 0 in user-land maps + * to in the kernel rnat. Do this by figuring out how many + * register slots we're beyond the user's backingstore and + * then computing the equivalent address in kernel space. + */ + num_regs = (long) ia64_rse_num_regs(ubspstore, urnat_addr + 1); + slot0_kaddr = ia64_rse_skip_regs(krbs, num_regs); + shift = ia64_rse_slot_num(slot0_kaddr); + rnat1_kaddr = ia64_rse_rnat_addr(slot0_kaddr); + rnat0_kaddr = rnat1_kaddr - 64; + + if (ubspstore + 63 > urnat_addr) { + /* some bits need to be place in pt->ar_rnat: */ + kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1); + pt->ar_rnat = (pt->ar_rnat & kmask) | (rnat & ~kmask); + } + /* + * Note: Section 11.1 of the EAS guarantees that bit 63 of an + * rnat slot is ignored. so we don't have to clear it here. + */ + rnat0 = (urnat << shift); + mask = ~0UL << shift; + if (rnat0_kaddr >= kbsp) { + sw->ar_rnat = (sw->ar_rnat & ~mask) | (rnat0 & mask); + } else if (rnat0_kaddr > krbs) { + *rnat0_kaddr = ((*rnat0_kaddr & ~mask) | (rnat0 & mask)); + } + + rnat1 = (urnat >> (63 - shift)); + mask = ~0UL >> (63 - shift); + if (rnat1_kaddr >= kbsp) { + sw->ar_rnat = (sw->ar_rnat & ~mask) | (rnat1 & mask); + } else if (rnat1_kaddr > krbs) { + *rnat1_kaddr = ((*rnat1_kaddr & ~mask) | (rnat1 & mask)); + } +} + +long +ia64_peek (struct pt_regs *regs, struct task_struct *child, unsigned long addr, long *val) +{ + unsigned long *bspstore, *krbs, krbs_num_regs, regnum, *rbs_end, *laddr; + struct switch_stack *child_stack; + struct pt_regs *child_regs; + size_t copied; + long ret; + + laddr = (unsigned long *) addr; + child_regs = ia64_task_regs(child); + child_stack = (struct switch_stack *) child_regs - 1; + bspstore = (unsigned long *) child_regs->ar_bspstore; + krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; + krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); + rbs_end = ia64_rse_skip_regs(bspstore, krbs_num_regs); + if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(rbs_end)) { + /* + * Attempt to read the RBS in an area that's actually + * on the kernel RBS => read the corresponding bits in + * the kernel RBS. + */ + if (ia64_rse_is_rnat_slot(laddr)) + ret = get_rnat(child_regs, child_stack, krbs, laddr); + else { + regnum = ia64_rse_num_regs(bspstore, laddr); + laddr = ia64_rse_skip_regs(krbs, regnum); + if (regnum >= krbs_num_regs) { + ret = 0; + } else { + if ((unsigned long) laddr >= (unsigned long) high_memory) { + printk("yikes: trying to access long at %p\n", laddr); + return -EIO; + } + ret = *laddr; + } + } + } else { + copied = access_process_vm(child, addr, &ret, sizeof(ret), 0); + if (copied != sizeof(ret)) + return -EIO; + } + *val = ret; + return 0; +} + +long +ia64_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr, long val) +{ + unsigned long *bspstore, *krbs, krbs_num_regs, regnum, *rbs_end, *laddr; + struct switch_stack *child_stack; + struct pt_regs *child_regs; + + laddr = (unsigned long *) addr; + child_regs = ia64_task_regs(child); + child_stack = (struct switch_stack *) child_regs - 1; + bspstore = (unsigned long *) child_regs->ar_bspstore; + krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; + krbs_num_regs = ia64_rse_num_regs(krbs, (unsigned long *) child_stack->ar_bspstore); + rbs_end = ia64_rse_skip_regs(bspstore, krbs_num_regs); + if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(rbs_end)) { + /* + * Attempt to write the RBS in an area that's actually + * on the kernel RBS => write the corresponding bits + * in the kernel RBS. + */ + if (ia64_rse_is_rnat_slot(laddr)) + put_rnat(child_regs, child_stack, krbs, laddr, val); + else { + regnum = ia64_rse_num_regs(bspstore, laddr); + laddr = ia64_rse_skip_regs(krbs, regnum); + if (regnum < krbs_num_regs) { + *laddr = val; + } + } + } else if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) { + return -EIO; + } + return 0; +} + +/* + * Ensure the state in child->thread.fph is up-to-date. + */ +static void +sync_fph (struct task_struct *child) +{ + if (ia64_psr(ia64_task_regs(child))->mfh && ia64_get_fpu_owner() == child) { + ia64_save_fpu(&child->thread.fph[0]); + child->thread.flags |= IA64_THREAD_FPH_VALID; + } + if (!(child->thread.flags & IA64_THREAD_FPH_VALID)) { + memset(&child->thread.fph, 0, sizeof(child->thread.fph)); + child->thread.flags |= IA64_THREAD_FPH_VALID; + } +} + +asmlinkage long +sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, + long arg4, long arg5, long arg6, long arg7, long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + struct switch_stack *child_stack; + struct pt_regs *child_regs; + struct task_struct *child; + unsigned long flags, *base; + long ret, regnum; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->flags & PF_PTRACED) + goto out; + current->flags |= PF_PTRACED; + ret = 0; + goto out; + } + + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + read_unlock(&tasklist_lock); + if (!child) + goto out; + ret = -EPERM; + if (pid == 1) /* no messing around with init! */ + 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) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out; + /* the same process cannot be attached many times */ + if (child->flags & PF_PTRACED) + goto out; + child->flags |= PF_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; + goto out; + } + ret = -ESRCH; + if (!(child->flags & PF_PTRACED)) + goto out; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out; + } + if (child->p_pptr != current) + goto out; + + switch (request) { + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: /* read word at location addr */ + ret = ia64_peek(regs, child, addr, &data); + if (ret == 0) { + ret = data; + regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */ + } + goto out; + + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: /* write the word at location addr */ + ret = ia64_poke(regs, child, addr, data); + goto out; + + case PTRACE_PEEKUSR: /* read the word at addr in the USER area */ + ret = -EIO; + if ((addr & 0x7) != 0) + goto out; + + if (addr < PT_CALLER_UNAT) { + /* accessing fph */ + sync_fph(child); + addr += (unsigned long) &child->thread.fph; + ret = *(unsigned long *) addr; + } else if (addr < PT_F9+16) { + /* accessing switch_stack or pt_regs: */ + child_regs = ia64_task_regs(child); + child_stack = (struct switch_stack *) child_regs - 1; + ret = *(unsigned long *) ((long) child_stack + addr - PT_CALLER_UNAT); + + if (addr == PT_AR_BSP) { + /* ret currently contains pt_regs.loadrs */ + unsigned long *rbs, *bspstore, ndirty; + + rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; + bspstore = (unsigned long *) child_regs->ar_bspstore; + ndirty = ia64_rse_num_regs(rbs, rbs + (ret >> 19)); + ret = (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); + } + } else { + if (addr >= PT_IBR) { + regnum = (addr - PT_IBR) >> 3; + base = &child->thread.ibr[0]; + } else { + regnum = (addr - PT_DBR) >> 3; + base = &child->thread.dbr[0]; + } + if (regnum >= 8) + goto out; + data = base[regnum]; + } + regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */ + goto out; + + case PTRACE_POKEUSR: /* write the word at addr in the USER area */ + ret = -EIO; + if ((addr & 0x7) != 0) + goto out; + + if (addr < PT_CALLER_UNAT) { + /* accessing fph */ + sync_fph(child); + addr += (unsigned long) &child->thread.fph; + *(unsigned long *) addr = data; + if (ret < 0) + goto out; + } else if (addr < PT_F9+16) { + /* accessing switch_stack or pt_regs */ + child_regs = ia64_task_regs(child); + child_stack = (struct switch_stack *) child_regs - 1; + + if (addr == PT_AR_BSP) { + /* compute the loadrs value based on bsp and bspstore: */ + unsigned long *rbs, *bspstore, ndirty, *kbsp; + + bspstore = (unsigned long *) child_regs->ar_bspstore; + ndirty = ia64_rse_num_regs(bspstore, (unsigned long *) data); + rbs = (unsigned long *) child + IA64_RBS_OFFSET/8; + kbsp = ia64_rse_skip_regs(rbs, ndirty); + data = (kbsp - rbs) << 19; + } + *(unsigned long *) ((long) child_stack + addr - PT_CALLER_UNAT) = data; + } else { + if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) { + child->thread.flags |= IA64_THREAD_DBG_VALID; + memset(current->thread.dbr, 0, sizeof current->thread.dbr); + memset(current->thread.ibr, 0, sizeof current->thread.ibr); + } + + if (addr >= PT_IBR) { + regnum = (addr - PT_IBR) >> 3; + base = &child->thread.ibr[0]; + } else { + regnum = (addr - PT_DBR) >> 3; + base = &child->thread.dbr[0]; + } + if (regnum >= 8) + goto out; + if (regnum & 1) { + /* force breakpoint to be effective a most for user-level: */ + data &= ~(0x7UL << 56); + } + base[regnum] = data; + } + ret = 0; + goto out; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: /* restart after signal. */ + ret = -EIO; + if (data > _NSIG) + goto out; + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + + /* make sure the single step/take-branch tra bits are not set: */ + ia64_psr(ia64_task_regs(child))->ss = 0; + ia64_psr(ia64_task_regs(child))->tb = 0; + + wake_up_process(child); + ret = 0; + goto out; + + case PTRACE_KILL: + /* + * Make the child exit. Best I can do is send it a + * sigkill. Perhaps it should be put in the status + * that it wants to exit. + */ + if (child->state == TASK_ZOMBIE) /* already dead */ + goto out; + child->exit_code = SIGKILL; + + /* make sure the single step/take-branch tra bits are not set: */ + ia64_psr(ia64_task_regs(child))->ss = 0; + ia64_psr(ia64_task_regs(child))->tb = 0; + + wake_up_process(child); + ret = 0; + goto out; + + case PTRACE_SINGLESTEP: /* let child execute for one instruction */ + case PTRACE_SINGLEBLOCK: + ret = -EIO; + if (data > _NSIG) + goto out; + + child->flags &= ~PF_TRACESYS; + if (request == PTRACE_SINGLESTEP) { + ia64_psr(ia64_task_regs(child))->ss = 1; + } else { + ia64_psr(ia64_task_regs(child))->tb = 1; + } + child->exit_code = data; + + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + goto out; + + case PTRACE_DETACH: /* detach a process that was attached. */ + ret = -EIO; + if (data > _NSIG) + goto out; + + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->exit_code = data; + write_lock_irqsave(&tasklist_lock, flags); + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); + + /* make sure the single step/take-branch tra bits are not set: */ + ia64_psr(ia64_task_regs(child))->ss = 0; + ia64_psr(ia64_task_regs(child))->tb = 0; + + wake_up_process(child); + ret = 0; + goto out; + + default: + ret = -EIO; + goto out; + } + out: + unlock_kernel(); + return ret; +} + +void +syscall_trace (void) +{ + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) + return; + current->exit_code = SIGTRAP; + set_current_state(TASK_STOPPED); + notify_parent(current, SIGCHLD); + schedule(); + /* + * This isn't the same as continuing with a signal, but it + * will do for normal use. strace only continues with a + * signal if the stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/sal.c linux/arch/ia64/kernel/sal.c --- v2.3.42/linux/arch/ia64/kernel/sal.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/sal.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,157 @@ +/* + * System Abstraction Layer (SAL) interface routines. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + */ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SAL_DEBUG + +spinlock_t sal_lock = SPIN_LOCK_UNLOCKED; + +static struct { + void *addr; /* function entry point */ + void *gpval; /* gp value to use */ +} pdesc; + +static long +default_handler (void) +{ + return -1; +} + +ia64_sal_handler ia64_sal = (ia64_sal_handler) default_handler; + +const char * +ia64_sal_strerror (long status) +{ + const char *str; + switch (status) { + case 0: str = "Call completed without error"; break; + case 1: str = "Effect a warm boot of the system to complete " + "the update"; break; + case -1: str = "Not implemented"; break; + case -2: str = "Invalid argument"; break; + case -3: str = "Call completed with error"; break; + case -4: str = "Virtual address not registered"; break; + case -5: str = "No information available"; break; + case -6: str = "Insufficient space to add the entry"; break; + case -7: str = "Invalid entry_addr value"; break; + case -8: str = "Invalid interrupt vector"; break; + case -9: str = "Requested memory not available"; break; + case -10: str = "Unable to write to the NVM device"; break; + case -11: str = "Invalid partition type specified"; break; + case -12: str = "Invalid NVM_Object id specified"; break; + case -13: str = "NVM_Object already has the maximum number " + "of partitions"; break; + case -14: str = "Insufficient space in partition for the " + "requested write sub-function"; break; + case -15: str = "Insufficient data buffer space for the " + "requested read record sub-function"; break; + case -16: str = "Scratch buffer required for the write/delete " + "sub-function"; break; + case -17: str = "Insufficient space in the NVM_Object for the " + "requested create sub-function"; break; + case -18: str = "Invalid value specified in the partition_rec " + "argument"; break; + case -19: str = "Record oriented I/O not supported for this " + "partition"; break; + case -20: str = "Bad format of record to be written or " + "required keyword variable not " + "specified"; break; + default: str = "Unknown SAL status code"; break; + } + return str; +} + +static void __init +ia64_sal_handler_init (void *entry_point, void *gpval) +{ + /* fill in the SAL procedure descriptor and point ia64_sal to it: */ + pdesc.addr = entry_point; + pdesc.gpval = gpval; + ia64_sal = (ia64_sal_handler) &pdesc; +} + + +void __init +ia64_sal_init (struct ia64_sal_systab *systab) +{ + unsigned long min, max; + char *p; + struct ia64_sal_desc_entry_point *ep; + int i; + + if (!systab) { + printk("Hmm, no SAL System Table.\n"); + return; + } + + if (strncmp(systab->signature, "SST_", 4) != 0) + printk("bad signature in system table!"); + + printk("SAL v%u.%02u: ia32bios=%s, oem=%.32s, product=%.32s\n", + systab->sal_rev_major, systab->sal_rev_minor, + systab->ia32_bios_present ? "present" : "absent", + systab->oem_id, systab->product_id); + + min = ~0UL; + max = 0; + + p = (char *) (systab + 1); + for (i = 0; i < systab->entry_count; i++) { + /* + * The first byte of each entry type contains the type desciptor. + */ + switch (*p) { + case SAL_DESC_ENTRY_POINT: + ep = (struct ia64_sal_desc_entry_point *) p; +#ifdef SAL_DEBUG + printk("sal[%d] - entry: pal_proc=0x%lx, sal_proc=0x%lx\n", + i, ep->pal_proc, ep->sal_proc); +#endif + ia64_pal_handler_init(__va(ep->pal_proc)); + ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp)); + break; + + case SAL_DESC_AP_WAKEUP: +#ifdef CONFIG_SMP + { + struct ia64_sal_desc_ap_wakeup *ap = (void *) p; +# ifdef SAL_DEBUG + printk("sal[%d] - wakeup type %x, 0x%lx\n", + i, ap->mechanism, ap->vector); +# endif + switch (ap->mechanism) { + case IA64_SAL_AP_EXTERNAL_INT: + ap_wakeup_vector = ap->vector; +# ifdef SAL_DEBUG + printk("SAL: AP wakeup using external interrupt; " + "vector 0x%lx\n", ap_wakeup_vector); +# endif + break; + + default: + printk("SAL: AP wakeup mechanism unsupported!\n"); + break; + } + break; + } +#endif + } + p += SAL_DESC_SIZE(*p); + } +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/sal_stub.S linux/arch/ia64/kernel/sal_stub.S --- v2.3.42/linux/arch/ia64/kernel/sal_stub.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/sal_stub.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,116 @@ +/* + * gcc currently does not conform to the ia-64 calling convention as far + * as returning function values are concerned. Instead of returning + * values up to 32 bytes in size in r8-r11, gcc returns any value + * bigger than a doubleword via a structure that's allocated by the + * caller and whose address is passed into the function. Since + * SAL_PROC returns values according to the calling convention, this + * stub takes care of copying r8-r11 to the place where gcc expects + * them. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + */ +#ifndef __GCC_MULTIREG_RETVALS__ + .text + .psr abi64 + .psr lsb + .lsb + + .align 16 + .global ia64_sal_stub +ia64_sal_stub: + /* + * Sheesh, the Cygnus backend passes the pointer to a return value structure in + * in0 whereas the HP backend passes it in r8. Don't you hate those little + * differences... + */ +#ifdef GCC_RETVAL_POINTER_IN_R8 + adds r2=-24,sp + adds sp=-48,sp + mov r14=rp + ;; + st8 [r2]=r8,8 // save pointer to return value + addl r3=@ltoff(ia64_sal),gp + ;; + ld8 r3=[r3] + st8 [r2]=gp,8 // save global pointer + ;; + ld8 r3=[r3] // fetch the value of ia64_sal + st8 [r2]=r14 // save return pointer + ;; + ld8 r2=[r3],8 // load function's entry point + ;; + ld8 gp=[r3] // load function's global pointer + ;; + mov b6=r2 + br.call.sptk.few rp=b6 +.ret0: adds r2=24,sp + ;; + ld8 r3=[r2],8 // restore pointer to return value + ;; + ld8 gp=[r2],8 // restore global pointer + st8 [r3]=r8,8 + ;; + ld8 r14=[r2] // restore return pointer + st8 [r3]=r9,8 + ;; + mov rp=r14 + st8 [r3]=r10,8 + ;; + st8 [r3]=r11,8 + adds sp=48,sp + br.sptk.few rp +#else + /* + * On input: + * in0 = pointer to return value structure + * in1 = index of SAL function to call + * in2..inN = remaining args to SAL call + */ + /* + * We allocate one input and eight output register such that the br.call instruction + * will rename in1-in7 to in0-in6---exactly what we want because SAL doesn't want to + * see the pointer to the return value structure. + */ + alloc r15=ar.pfs,1,0,8,0 + + adds r2=-24,sp + adds sp=-48,sp + mov r14=rp + ;; + st8 [r2]=r15,8 // save ar.pfs + addl r3=@ltoff(ia64_sal),gp + ;; + ld8 r3=[r3] // get address of ia64_sal + st8 [r2]=gp,8 // save global pointer + ;; + ld8 r3=[r3] // get value of ia64_sal + st8 [r2]=r14,8 // save return address (rp) + ;; + ld8 r2=[r3],8 // load function's entry point + ;; + ld8 gp=[r3] // load function's global pointer + mov b6=r2 + br.call.sptk.few rp=b6 // make SAL call +.ret0: adds r2=24,sp + ;; + ld8 r15=[r2],8 // restore ar.pfs + ;; + ld8 gp=[r2],8 // restore global pointer + st8 [in0]=r8,8 // store 1. dword of return value + ;; + ld8 r14=[r2] // restore return address (rp) + st8 [in0]=r9,8 // store 2. dword of return value + ;; + mov rp=r14 + st8 [in0]=r10,8 // store 3. dword of return value + ;; + st8 [in0]=r11,8 + adds sp=48,sp // pop stack frame + mov ar.pfs=r15 + br.ret.sptk.few rp +#endif + + .endp ia64_sal_stub +#endif /* __GCC_MULTIREG_RETVALS__ */ diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/semaphore.c linux/arch/ia64/kernel/semaphore.c --- v2.3.42/linux/arch/ia64/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/semaphore.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,336 @@ +/* + * IA-64 semaphore implementation (derived from x86 version). + * + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang + */ + +/* + * Semaphores are implemented using a two-way counter: The "count" + * variable is decremented for each process that tries to aquire the + * semaphore, while the "sleepers" variable is a count of such + * aquires. + * + * Notably, the inline "up()" and "down()" functions can efficiently + * test if they need to do any extra work (up needs to do something + * only if count was negative before the increment operation. + * + * "sleepers" and the contention routine ordering is protected by the + * semaphore spinlock. + * + * Note that these functions are only called when there is contention + * on the lock, and as such all this is the "non-critical" part of the + * whole semaphore business. The critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +#include + +#include + +/* + * Logic: + * - Only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - When we go from a non-negative count to a negative do we + * (a) synchronize with the "sleepers" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +void +__up (struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; + +void +__down (struct semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE; + add_wait_queue_exclusive(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + wake_up(&sem->wait); +} + +int +__down_interruptible (struct semaphore * sem) +{ + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE; + add_wait_queue_exclusive(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers ++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + if (signal_pending(current)) { + retval = -EINTR; + sem->sleepers = 0; + atomic_add(sleepers, &sem->count); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. The + * "-1" is because we're still hoping to get + * the lock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); + return retval; +} + +/* + * Trylock failed - make sure we correct for having decremented the + * count. + */ +int +__down_trylock (struct semaphore *sem) +{ + int sleepers; + + spin_lock_irq(&semaphore_lock); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers, &sem->count)) + wake_up(&sem->wait); + + spin_unlock_irq(&semaphore_lock); + return 1; +} + +/* + * Helper routines for rw semaphores. These could be optimized some + * more, but since they're off the critical path, I prefer clarity for + * now... + */ + +/* + * This gets called if we failed to acquire the lock, but we're biased + * to acquire the lock by virtue of causing the count to change from 0 + * to -1. Being biased, we sleep and attempt to grab the lock until + * we succeed. When this function returns, we own the lock. + */ +static inline void +down_read_failed_biased (struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */ + + for (;;) { + if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!sem->read_bias_granted) + schedule(); + } + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +/* + * This gets called if we failed to aquire the lock and we are not + * biased to acquire the lock. We undo the decrement that was + * done earlier, go to sleep, and then attempt to re-acquire the + * lock afterwards. + */ +static inline void +down_read_failed (struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + /* + * Undo the decrement we did in down_read() and check if we + * need to wake up someone. + */ + __up_read(sem); + + add_wait_queue(&sem->wait, &wait); + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (sem->count >= 0) + break; + schedule(); + } + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +/* + * Wait for the lock to become unbiased. Readers are non-exclusive. + */ +void +__down_read_failed (struct rw_semaphore *sem, long count) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + while (1) { + if (count == -1) { + down_read_failed_biased(sem); + return; + } + /* unbiased */ + down_read_failed(sem); + + count = ia64_fetch_and_add(-1, &sem->count); + if (count >= 0) + return; + } +} + +static inline void +down_write_failed_biased (struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + /* put ourselves at the end of the list */ + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); + + for (;;) { + if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (!sem->write_bias_granted) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* + * If the lock is currently unbiased, awaken the sleepers + * FIXME: this wakes up the readers early in a bit of a + * stampede -> bad! + */ + if (sem->count >= 0) + wake_up(&sem->wait); +} + + +static inline void +down_write_failed (struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + __up_write(sem); /* this takes care of granting the lock */ + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (sem->count < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + if (sem->count >= 0) + break; /* we must attempt to aquire or bias the lock */ + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + + +/* + * Wait for the lock to become unbiased. Since we're a writer, we'll + * make ourselves exclusive. + */ +void +__down_write_failed (struct rw_semaphore *sem, long count) +{ + long old_count; + + while (1) { + if (count == -RW_LOCK_BIAS) { + down_write_failed_biased(sem); + return; + } + down_write_failed(sem); + + do { + old_count = sem->count; + count = old_count - RW_LOCK_BIAS; + } while (cmpxchg(&sem->count, old_count, count) != old_count); + + if (count == 0) + return; + } +} + +void +__rwsem_wake (struct rw_semaphore *sem, long count) +{ + wait_queue_head_t *wq; + + if (count == 0) { + /* wake a writer */ + if (xchg(&sem->write_bias_granted, 1)) + BUG(); + wq = &sem->write_bias_wait; + } else { + /* wake reader(s) */ + if (xchg(&sem->read_bias_granted, 1)) + BUG(); + wq = &sem->wait; + } + wake_up(wq); /* wake up everyone on the wait queue */ +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c --- v2.3.42/linux/arch/ia64/kernel/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/setup.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,326 @@ +/* + * Architecture-specific setup. + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang + * Copyright (C) 1998, 1999 Stephane Eranian + * Copyright (C) 2000, Rohit Seth + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * + * 02/04/00 D.Mosberger some more get_cpuinfo fixes... + * 02/01/00 R.Seth fixed get_cpuinfo for SMP + * 01/07/99 S.Eranian added the support for command line argument + * 06/24/99 W.Drummond added boot_cpu_data. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern char _end; + +/* cpu_data[bootstrap_processor] is data for the bootstrap processor: */ +struct cpuinfo_ia64 cpu_data[NR_CPUS]; + +unsigned long ia64_cycles_per_usec; +struct ia64_boot_param ia64_boot_param; +struct screen_info screen_info; +unsigned long cpu_initialized = 0; +/* This tells _start which CPU is booting. */ +int cpu_now_booting = 0; + +#define COMMAND_LINE_SIZE 512 + +char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */ + +static int +find_max_pfn (unsigned long start, unsigned long end, void *arg) +{ + unsigned long *max_pfn = arg, pfn; + + pfn = (PAGE_ALIGN(end - 1) - PAGE_OFFSET) >> PAGE_SHIFT; + if (pfn > *max_pfn) + *max_pfn = pfn; + return 0; +} + +static int +free_available_memory (unsigned long start, unsigned long end, void *arg) +{ +# define KERNEL_END ((unsigned long) &_end) +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +# define MAX(a,b) ((a) > (b) ? (a) : (b)) + unsigned long range_start, range_end; + + range_start = MIN(start, KERNEL_START); + range_end = MIN(end, KERNEL_START); + + /* + * XXX This should not be necessary, but the bootmem allocator + * is broken and fails to work correctly when the starting + * address is not properly aligned. + */ + range_start = PAGE_ALIGN(range_start); + + if (range_start < range_end) + free_bootmem(__pa(range_start), range_end - range_start); + + range_start = MAX(start, KERNEL_END); + range_end = MAX(end, KERNEL_END); + + /* + * XXX This should not be necessary, but the bootmem allocator + * is broken and fails to work correctly when the starting + * address is not properly aligned. + */ + range_start = PAGE_ALIGN(range_start); + + if (range_start < range_end) + free_bootmem(__pa(range_start), range_end - range_start); + + return 0; +} + +void __init +setup_arch (char **cmdline_p) +{ + unsigned long max_pfn, bootmap_start, bootmap_size; + + /* + * The secondary bootstrap loader passes us the boot + * parameters at the beginning of the ZERO_PAGE, so let's + * stash away those values before ZERO_PAGE gets cleared out. + */ + memcpy(&ia64_boot_param, (void *) ZERO_PAGE_ADDR, sizeof(ia64_boot_param)); + + efi_init(); + + max_pfn = 0; + efi_memmap_walk(find_max_pfn, &max_pfn); + + /* + * This is wrong, wrong, wrong. Darn it, you'd think if they + * change APIs, they'd do things for the better. Grumble... + */ + bootmap_start = PAGE_ALIGN(__pa(&_end)); + bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn); + + efi_memmap_walk(free_available_memory, 0); + + reserve_bootmem(bootmap_start, bootmap_size); +#if 0 + /* XXX fix me */ + init_mm.start_code = (unsigned long) &_stext; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + + code_resource.start = virt_to_bus(&_text); + code_resource.end = virt_to_bus(&_etext) - 1; + data_resource.start = virt_to_bus(&_etext); + data_resource.end = virt_to_bus(&_edata) - 1; +#endif + + /* process SAL system table: */ + ia64_sal_init(efi.sal_systab); + + *cmdline_p = __va(ia64_boot_param.command_line); + strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ + + printk("args to kernel: %s\n", *cmdline_p); + +#ifndef CONFIG_SMP + cpu_init(); + identify_cpu(&cpu_data[0]); +#endif + + if (efi.acpi) { + /* Parse the ACPI tables */ + acpi_parse(efi.acpi); + } + +#ifdef CONFIG_IA64_GENERIC + machvec_init(acpi_get_sysname()); +#endif + +#ifdef CONFIG_VT +# if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; +# elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +# endif +#endif + platform_setup(cmdline_p); +} + +/* + * Display cpu info for all cpu's. + */ +int +get_cpuinfo (char *buffer) +{ + char family[32], model[32], features[128], *cp, *p = buffer; + struct cpuinfo_ia64 *c; + unsigned long mask; + + for (c = cpu_data; c < cpu_data + NR_CPUS; ++c) { + if (!(cpu_initialized & (1UL << (c - cpu_data)))) + continue; + + mask = c->features; + + if (c->family == 7) + memcpy(family, "IA-64", 6); + else + sprintf(family, "%u", c->family); + + switch (c->model) { + case 0: strcpy(model, "Itanium"); break; + default: sprintf(model, "%u", c->model); break; + } + + /* build the feature string: */ + memcpy(features, " standard", 10); + cp = features; + if (mask & 1) { + strcpy(cp, " branchlong"); + cp = strchr(cp, '\0'); + mask &= ~1UL; + } + if (mask) + sprintf(cp, " 0x%lx", mask); + + p += sprintf(buffer, + "CPU# %lu\n" + "\tvendor : %s\n" + "\tfamily : %s\n" + "\tmodel : %s\n" + "\trevision : %u\n" + "\tarchrev : %u\n" + "\tfeatures :%s\n" /* don't change this---it _is_ right! */ + "\tcpu number : %lu\n" + "\tcpu regs : %u\n" + "\tcpu MHz : %lu.%06lu\n" + "\titc MHz : %lu.%06lu\n" + "\tBogoMIPS : %lu.%02lu\n\n", + c - cpu_data, c->vendor, family, model, c->revision, c->archrev, + features, + c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000, + c->itc_freq / 1000000, c->itc_freq % 1000000, + loops_per_sec() / 500000, (loops_per_sec() / 5000) % 100); + } + return p - buffer; +} + +void +identify_cpu (struct cpuinfo_ia64 *c) +{ + union { + unsigned long bits[5]; + struct { + /* id 0 & 1: */ + char vendor[16]; + + /* id 2 */ + u64 ppn; /* processor serial number */ + + /* id 3: */ + unsigned number : 8; + unsigned revision : 8; + unsigned model : 8; + unsigned family : 8; + unsigned archrev : 8; + unsigned reserved : 24; + + /* id 4: */ + u64 features; + } field; + } cpuid; + int i; + + for (i = 0; i < 5; ++i) { + cpuid.bits[i] = ia64_get_cpuid(i); + } + +#ifdef CONFIG_SMP + /* + * XXX Instead of copying the ITC info from the bootstrap + * processor, ia64_init_itm() should be done per CPU. That + * should get you the right info. --davidm 1/24/00 + */ + if (c != &cpu_data[bootstrap_processor]) { + memset(c, 0, sizeof(struct cpuinfo_ia64)); + c->proc_freq = cpu_data[bootstrap_processor].proc_freq; + c->itc_freq = cpu_data[bootstrap_processor].itc_freq; + c->cyc_per_usec = cpu_data[bootstrap_processor].cyc_per_usec; + c->usec_per_cyc = cpu_data[bootstrap_processor].usec_per_cyc; + } +#else + memset(c, 0, sizeof(struct cpuinfo_ia64)); +#endif + + memcpy(c->vendor, cpuid.field.vendor, 16); +#ifdef CONFIG_IA64_SOFTSDV_HACKS + /* BUG: SoftSDV doesn't support the cpuid registers. */ + if (c->vendor[0] == '\0') + memcpy(c->vendor, "Intel", 6); +#endif + c->ppn = cpuid.field.ppn; + c->number = cpuid.field.number; + c->revision = cpuid.field.revision; + c->model = cpuid.field.model; + c->family = cpuid.field.family; + c->archrev = cpuid.field.archrev; + c->features = cpuid.field.features; +#ifdef CONFIG_SMP + c->loops_per_sec = loops_per_sec; +#endif +} + +/* + * cpu_init() initializes state that is per-CPU. This function acts + * as a 'CPU state barrier', nothing should get across. + */ +void +cpu_init (void) +{ + int nr = smp_processor_id(); + + /* Clear the stack memory reserved for pt_regs: */ + memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); + + /* + * Initialize default control register to defer speculative + * faults. On a speculative load, we want to defer access + * right, key miss, and key permission faults. We currently + * do NOT defer TLB misses, page-not-present, access bit, or + * debug faults but kernel code should not rely on any + * particular setting of these bits. + */ + ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP); + ia64_set_fpu_owner(0); /* initialize ar.k5 */ + + if (test_and_set_bit(nr, &cpu_initialized)) { + printk("CPU#%d already initialized!\n", nr); + machine_halt(); + } + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c --- v2.3.42/linux/arch/ia64/kernel/signal.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/signal.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,537 @@ +/* + * Architecture-specific signal handling support. + * + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang + * + * Derived from i386 and Alpha versions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DEBUG_SIG 0 +#define STACK_ALIGN 16 /* minimal alignment for stack pointer */ +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +#if _NSIG_WORDS > 1 +# define PUT_SIGSET(k,u) __copy_to_user((u)->sig, (k)->sig, sizeof(sigset_t)) +# define GET_SIGSET(k,u) __copy_from_user((k)->sig, (u)->sig, sizeof(sigset_t)) +#else +# define PUT_SIGSET(k,u) __put_user((k)->sig[0], &(u)->sig[0]) +# define GET_SIGSET(k,u) __get_user((k)->sig[0], &(u)->sig[0]) +#endif + +struct sigframe { + struct siginfo info; + struct sigcontext sc; +}; + +extern long sys_wait4 (int, int *, int, struct rusage *); +extern long ia64_do_signal (sigset_t *, struct pt_regs *, long); /* forward decl */ + +long +ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct pt_regs *pt) +{ + sigset_t oldset, set; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + if (GET_SIGSET(&set, uset)) + return -EFAULT; + + sigdelsetmask(&set, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + { + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); + } + spin_unlock_irq(¤t->sigmask_lock); + + /* + * The return below usually returns to the signal handler. We need to + * pre-set the correct error code here to ensure that the right values + * get saved in sigcontext by ia64_do_signal. + */ + pt->r8 = EINTR; + pt->r10 = -1; + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (ia64_do_signal(&oldset, pt, 1)) + return -EINTR; + } +} + +asmlinkage long +sys_sigaltstack (const stack_t *uss, stack_t *uoss, long arg2, long arg3, long arg4, + long arg5, long arg6, long arg7, long stack) +{ + struct pt_regs *pt = (struct pt_regs *) &stack; + + return do_sigaltstack(uss, uoss, pt->r12); +} + +static long +restore_sigcontext (struct sigcontext *sc, struct pt_regs *pt) +{ + struct switch_stack *sw = (struct switch_stack *) pt - 1; + unsigned long ip, flags, nat, um; + long err; + + /* restore scratch that always needs gets updated during signal delivery: */ + err = __get_user(flags, &sc->sc_flags); + + err |= __get_user(nat, &sc->sc_nat); + err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */ + err |= __get_user(pt->ar_fpsr, &sc->sc_ar_fpsr); + err |= __get_user(pt->ar_pfs, &sc->sc_ar_pfs); + err |= __get_user(um, &sc->sc_um); /* user mask */ + err |= __get_user(pt->ar_rsc, &sc->sc_ar_rsc); + err |= __get_user(pt->ar_ccv, &sc->sc_ar_ccv); + err |= __get_user(pt->ar_unat, &sc->sc_ar_unat); + err |= __get_user(pt->pr, &sc->sc_pr); /* predicates */ + err |= __get_user(pt->b0, &sc->sc_br[0]); /* b0 (rp) */ + err |= __get_user(pt->b6, &sc->sc_br[6]); + err |= __copy_from_user(&pt->r1, &sc->sc_gr[1], 3*8); /* r1-r3 */ + err |= __copy_from_user(&pt->r8, &sc->sc_gr[8], 4*8); /* r8-r11 */ + err |= __copy_from_user(&pt->r12, &sc->sc_gr[12], 4*8); /* r12-r15 */ + err |= __copy_from_user(&pt->r16, &sc->sc_gr[16], 16*8); /* r16-r31 */ + + /* establish new instruction pointer: */ + pt->cr_iip = ip & ~0x3UL; + ia64_psr(pt)->ri = ip & 0x3; + pt->cr_ipsr = (pt->cr_ipsr & ~IA64_PSR_UM) | (um & IA64_PSR_UM); + + ia64_put_nat_bits (pt, sw, nat); /* restore the original scratch NaT bits */ + + if (flags & IA64_SC_FLAG_FPH_VALID) { + struct task_struct *fpu_owner = ia64_get_fpu_owner(); + + __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16); + if (fpu_owner == current) { + __ia64_load_fpu(current->thread.fph); + } + } + return err; +} + +/* + * When we get here, ((struct switch_stack *) pt - 1) is a + * switch_stack frame that has no defined value. Upon return, we + * expect sw->caller_unat to contain the new unat value. The reason + * we use a full switch_stack frame is so everything is symmetric + * with ia64_do_signal(). + */ +long +ia64_rt_sigreturn (struct pt_regs *pt) +{ + extern char ia64_strace_leave_kernel, ia64_leave_kernel; + struct sigcontext *sc; + struct siginfo si; + sigset_t set; + long retval; + + sc = &((struct sigframe *) (pt->r12 + 16))->sc; + + /* + * When we return to the previously executing context, r8 and + * r10 have already been setup the way we want them. Indeed, + * if the signal wasn't delivered while in a system call, we + * must not touch r8 or r10 as otherwise user-level stat could + * be corrupted. + */ + retval = (long) &ia64_leave_kernel | 1; + if ((current->flags & PF_TRACESYS) + && (sc->sc_flags & IA64_SC_FLAG_IN_SYSCALL)) + retval = (long) &ia64_strace_leave_kernel; + + if (!access_ok(VERIFY_READ, sc, sizeof(*sc))) + goto give_sigsegv; + + if (GET_SIGSET(&set, &sc->sc_mask)) + goto give_sigsegv; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(sc, pt)) + goto give_sigsegv; + +#if DEBUG_SIG + printk("SIG return (%s:%d): sp=%lx ip=%lx\n", + current->comm, current->pid, pt->r12, pt->cr_iip); +#endif + /* + * It is more difficult to avoid calling this function than to + * call it and ignore errors. + */ + do_sigaltstack(&sc->sc_stack, 0, pt->r12); + return retval; + + give_sigsegv: + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = SI_KERNEL; + si.si_pid = current->pid; + si.si_uid = current->uid; + si.si_addr = sc; + force_sig_info(SIGSEGV, &si, current); + return retval; +} + +/* + * This does just the minimum required setup of sigcontext. + * Specifically, it only installs data that is either not knowable at + * the user-level or that gets modified before execution in the + * trampoline starts. Everything else is done at the user-level. + */ +static long +setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct pt_regs *pt) +{ + struct switch_stack *sw = (struct switch_stack *) pt - 1; + struct task_struct *fpu_owner = ia64_get_fpu_owner(); + unsigned long flags = 0, ifs, nat; + long err; + + ifs = pt->cr_ifs; + + if (on_sig_stack((unsigned long) sc)) + flags |= IA64_SC_FLAG_ONSTACK; + if ((ifs & (1UL << 63)) == 0) { + /* if cr_ifs isn't valid, we got here through a syscall */ + flags |= IA64_SC_FLAG_IN_SYSCALL; + } + if ((fpu_owner == current) || (current->thread.flags & IA64_THREAD_FPH_VALID)) { + flags |= IA64_SC_FLAG_FPH_VALID; + if (fpu_owner == current) { + __ia64_save_fpu(current->thread.fph); + } + __copy_to_user(&sc->sc_fr[32], current->thread.fph, 96*16); + } + + /* + * Note: sw->ar_unat is UNDEFINED unless the process is being + * PTRACED. However, this is OK because the NaT bits of the + * preserved registers (r4-r7) are never being looked at by + * the signal handler (register r4-r7 are used instead). + */ + nat = ia64_get_nat_bits(pt, sw); + + err = __put_user(flags, &sc->sc_flags); + err |= __put_user(nat, &sc->sc_nat); + err |= PUT_SIGSET(mask, &sc->sc_mask); + err |= __put_user(pt->cr_ipsr & IA64_PSR_UM, &sc->sc_um); + err |= __put_user(pt->ar_rsc, &sc->sc_ar_rsc); + err |= __put_user(pt->ar_ccv, &sc->sc_ar_ccv); + err |= __put_user(pt->ar_unat, &sc->sc_ar_unat); /* ar.unat */ + err |= __put_user(pt->ar_fpsr, &sc->sc_ar_fpsr); /* ar.fpsr */ + err |= __put_user(pt->ar_pfs, &sc->sc_ar_pfs); + err |= __put_user(pt->pr, &sc->sc_pr); /* predicates */ + err |= __put_user(pt->b0, &sc->sc_br[0]); /* b0 (rp) */ + err |= __put_user(pt->b6, &sc->sc_br[6]); /* b6 */ + err |= __put_user(pt->b7, &sc->sc_br[7]); /* b7 */ + + err |= __copy_to_user(&sc->sc_gr[1], &pt->r1, 3*8); /* r1-r3 */ + err |= __copy_to_user(&sc->sc_gr[8], &pt->r8, 4*8); /* r8-r11 */ + err |= __copy_to_user(&sc->sc_gr[12], &pt->r12, 4*8); /* r12-r15 */ + err |= __copy_to_user(&sc->sc_gr[16], &pt->r16, 16*8); /* r16-r31 */ + + err |= __put_user(pt->cr_iip + ia64_psr(pt)->ri, &sc->sc_ip); + err |= __put_user(pt->r12, &sc->sc_gr[12]); /* r12 */ + return err; +} + +static long +setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *pt) +{ + struct switch_stack *sw = (struct switch_stack *) pt - 1; + extern char ia64_sigtramp[], __start_gate_section[]; + unsigned long tramp_addr, new_rbs = 0; + struct sigframe *frame; + struct siginfo si; + long err; + + frame = (void *) pt->r12; + tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section); + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack((unsigned long) frame)) { + new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); + frame = (void *) ((current->sas_ss_sp + current->sas_ss_size) + & ~(STACK_ALIGN - 1)); + } + frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err = __copy_to_user(&frame->info, info, sizeof(siginfo_t)); + + err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp); + err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size); + err |= __put_user(sas_ss_flags(pt->r12), &frame->sc.sc_stack.ss_flags); + err |= setup_sigcontext(&frame->sc, set, pt); + + if (err) + goto give_sigsegv; + + pt->r12 = (unsigned long) frame - 16; /* new stack pointer */ + pt->r2 = sig; /* signal number */ + pt->r3 = (unsigned long) ka->sa.sa_handler; /* addr. of handler's proc. descriptor */ + pt->r15 = new_rbs; + pt->ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ + pt->cr_iip = tramp_addr; + ia64_psr(pt)->ri = 0; /* start executing in first slot */ + + /* + * Note: this affects only the NaT bits of the scratch regs + * (the ones saved in pt_regs, which is exactly what we want. + * The NaT bits for the preserved regs (r4-r7) are in + * sw->ar_unat iff this process is being PTRACED. + */ + sw->caller_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n", + current->comm, current->pid, sig, pt->r12, pt->cr_iip, pt->r3); +#endif + return 1; + + give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = SI_KERNEL; + si.si_pid = current->pid; + si.si_uid = current->uid; + si.si_addr = frame; + force_sig_info(SIGSEGV, &si, current); + return 0; +} + +static long +handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, + struct pt_regs *pt) +{ +#ifdef CONFIG_IA32_SUPPORT + if (IS_IA32_PROCESS(pt)) { + /* send signal to IA-32 process */ + if (!ia32_setup_frame1(sig, ka, info, oldset, pt)) + return 0; + } else +#endif + /* send signal to IA-64 process */ + if (!setup_frame(sig, ka, info, oldset, pt)) + return 0; + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sigmask_lock); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + sigaddset(¤t->blocked, sig); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + } + return 1; +} + +/* + * When we get here, `pt' points to struct pt_regs and ((struct + * switch_stack *) pt - 1) points to a switch stack structure. + * HOWEVER, in the normal case, the ONLY value valid in the + * switch_stack is the caller_unat field. The entire switch_stack is + * valid ONLY if current->flags has PF_PTRACED set. + * + * Note that `init' is a special process: it doesn't get signals it + * doesn't want to handle. Thus you cannot kill init even with a + * SIGKILL even by mistake. + * + * Note that we go through the signals twice: once to check the + * signals that the kernel can handle, and then we build all the + * user-level signal handling stack-frames in one go after that. + */ +long +ia64_do_signal (sigset_t *oldset, struct pt_regs *pt, long in_syscall) +{ + struct k_sigaction *ka; + siginfo_t info; + long restart = in_syscall; + + /* + * In the ia64_leave_kernel code path, we want the common case + * to go fast, which is why we may in certain cases get here + * from kernel mode. Just return without doing anything if so. + */ + if (!user_mode(pt)) + return 0; + + if (!oldset) + oldset = ¤t->blocked; + + if (pt->r10 != -1) { + /* + * A system calls has to be restarted only if one of + * the error codes ERESTARTNOHAND, ERESTARTSYS, or + * ERESTARTNOINTR is returned. If r10 isn't -1 then + * r8 doesn't hold an error code and we don't need to + * restart the syscall, so we set in_syscall to zero. + */ + restart = 0; + } + + for (;;) { + unsigned long signr; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + if (!signr) + break; + + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + current->exit_code = signr; + set_current_state(TASK_STOPPED); + notify_parent(current, SIGCHLD); + schedule(); + signr = current->exit_code; + + /* We're back. Did the debugger cancel the sig? */ + if (!signr) + continue; + current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ + if (signr == SIGSTOP) + continue; + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); + continue; + } + } + + ka = ¤t->sig->action[signr - 1]; + if (ka->sa.sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; + continue; + } + + if (ka->sa.sa_handler == SIG_DFL) { + int exit_code = signr; + + /* Init gets no signals it doesn't want. */ + if (current->pid == 1) + continue; + + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + /* FALLTHRU */ + + case SIGSTOP: + set_current_state(TASK_STOPPED); + current->exit_code = signr; + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags + & SA_NOCLDSTOP)) + notify_parent(current, SIGCHLD); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: + if (do_coredump(signr, pt)) + exit_code |= 0x80; + /* FALLTHRU */ + + default: + lock_kernel(); + sigaddset(¤t->signal, signr); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + if (restart) { + switch (pt->r8) { + case ERESTARTSYS: + if ((ka->sa.sa_flags & SA_RESTART) == 0) { + case ERESTARTNOHAND: + pt->r8 = EINTR; + /* note: pt->r10 is already -1 */ + break; + } + case ERESTARTNOINTR: + ia64_decrement_ip(pt); + } + } + + /* Whee! Actually deliver the signal. If the + delivery failed, we need to continue to iterate in + this loop so we can deliver the SIGSEGV... */ + if (handle_signal(signr, ka, &info, oldset, pt)) + return 1; + } + + /* Did we come from a system call? */ + if (restart) { + /* Restart the system call - no handlers present */ + if (pt->r8 == ERESTARTNOHAND || + pt->r8 == ERESTARTSYS || + pt->r8 == ERESTARTNOINTR) { + /* + * Note: the syscall number is in r15 which is + * saved in pt_regs so all we need to do here + * is adjust ip so that the "break" + * instruction gets re-executed. + */ + ia64_decrement_ip(pt); + } + } + return 0; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c --- v2.3.42/linux/arch/ia64/kernel/smp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/smp.c Wed Feb 9 19:45:43 2000 @@ -0,0 +1,777 @@ +/* + * SMP Support + * + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 1999 David Mosberger-Tang + * + * Lots of stuff stolen from arch/alpha/kernel/smp.c + * + * 99/10/05 davidm Update to bring it in sync with new command-line processing scheme. + */ +#define __KERNEL_SYSCALLS__ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_KDB +#include +void smp_kdb_interrupt (struct pt_regs* regs); +void kdb_global(int cpuid); +extern unsigned long smp_kdb_wait; +extern int kdb_new_cpu; +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int cpu_idle(void * unused); +extern void _start(void); + +extern int cpu_now_booting; /* Used by head.S to find idle task */ +extern unsigned long cpu_initialized; /* Bitmap of available cpu's */ +extern struct cpuinfo_ia64 cpu_data[NR_CPUS]; /* Duh... */ + +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; + +#ifdef CONFIG_KDB +unsigned long cpu_online_map = 1; +#endif + +volatile int cpu_number_map[NR_CPUS] = { -1, }; /* SAPIC ID -> Logical ID */ +volatile int __cpu_logical_map[NR_CPUS] = { -1, }; /* logical ID -> SAPIC ID */ +int smp_num_cpus = 1; +int bootstrap_processor = -1; /* SAPIC ID of BSP */ +int smp_threads_ready = 0; /* Set when the idlers are all forked */ +unsigned long ipi_base_addr = IPI_DEFAULT_BASE_ADDR; /* Base addr of IPI table */ +cycles_t cacheflush_time = 0; +unsigned long ap_wakeup_vector = -1; /* External Int to use to wakeup AP's */ +static int max_cpus = -1; /* Command line */ +static unsigned long ipi_op[NR_CPUS]; +struct smp_call_struct { + void (*func) (void *info); + void *info; + long wait; + atomic_t unstarted_count; + atomic_t unfinished_count; +}; +static struct smp_call_struct *smp_call_function_data; + +#ifdef CONFIG_KDB +unsigned long smp_kdb_wait = 0; /* Bitmask of waiters */ +#endif + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC +extern spinlock_t ivr_read_lock; +#endif + +int use_xtp = 0; /* XXX */ + +#define IPI_RESCHEDULE 0 +#define IPI_CALL_FUNC 1 +#define IPI_CPU_STOP 2 +#define IPI_KDB_INTERRUPT 4 + +/* + * Setup routine for controlling SMP activation + * + * Command-line option of "nosmp" or "maxcpus=0" will disable SMP + * activation entirely (the MPS table probe still happens, though). + * + * Command-line option of "maxcpus=", where is an integer + * greater than 0, limits the maximum number of CPUs activated in + * SMP mode to . + */ + +static int __init nosmp(char *str) +{ + max_cpus = 0; + return 1; +} + +__setup("nosmp", nosmp); + +static int __init maxcpus(char *str) +{ + get_option(&str, &max_cpus); + return 1; +} + +__setup("maxcpus=", maxcpus); + +/* + * Yoink this CPU from the runnable list... + */ +void +halt_processor(void) +{ + clear_bit(smp_processor_id(), &cpu_initialized); + max_xtp(); + __cli(); + for (;;) + ; + +} + +void +handle_IPI(int irq, void *dev_id, struct pt_regs *regs) +{ + int this_cpu = smp_processor_id(); + unsigned long *pending_ipis = &ipi_op[this_cpu]; + unsigned long ops; + + /* Count this now; we may make a call that never returns. */ + cpu_data[this_cpu].ipi_count++; + + mb(); /* Order interrupt and bit testing. */ + while ((ops = xchg(pending_ipis, 0)) != 0) { + mb(); /* Order bit clearing and data access. */ + do { + unsigned long which; + + which = ffz(~ops); + ops &= ~(1 << which); + + switch (which) { + case IPI_RESCHEDULE: + /* + * Reschedule callback. Everything to be done is done by the + * interrupt return path. + */ + break; + + case IPI_CALL_FUNC: + { + struct smp_call_struct *data; + void (*func)(void *info); + void *info; + int wait; + + data = smp_call_function_data; + func = data->func; + info = data->info; + wait = data->wait; + + mb(); + atomic_dec (&data->unstarted_count); + + /* At this point the structure may be gone unless wait is true. */ + (*func)(info); + + /* Notify the sending CPU that the task is done. */ + mb(); + if (wait) + atomic_dec (&data->unfinished_count); + } + break; + + case IPI_CPU_STOP: + halt_processor(); + break; + +#ifdef CONFIG_KDB + case IPI_KDB_INTERRUPT: + smp_kdb_interrupt(regs); + break; +#endif + + default: + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); + break; + } /* Switch */ + } while (ops); + + mb(); /* Order data access and bit testing. */ + } +} + +static inline void +send_IPI(int dest_cpu, unsigned char vector) +{ + unsigned long ipi_addr; + unsigned long ipi_data; +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + unsigned long flags; +#endif + + ipi_data = vector; + ipi_addr = ipi_base_addr | ((dest_cpu << 8) << 4); /* 16-bit SAPIC ID's; assume CPU bus 0 */ + mb(); + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + /* + * Disable IVR reads + */ + spin_lock_irqsave(&ivr_read_lock, flags); + writeq(ipi_data, ipi_addr); + spin_unlock_irqrestore(&ivr_read_lock, flags); +#else + writeq(ipi_data, ipi_addr); +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ + +} + +static inline void +send_IPI_single(int dest_cpu, int op) +{ + + if (dest_cpu == -1) + return; + + ipi_op[dest_cpu] |= (1 << op); + send_IPI(dest_cpu, IPI_IRQ); +} + +static inline void +send_IPI_allbutself(int op) +{ + int i; + int cpu_id = 0; + + for (i = 0; i < smp_num_cpus; i++) { + cpu_id = __cpu_logical_map[i]; + if (cpu_id != smp_processor_id()) + send_IPI_single(cpu_id, op); + } +} + +static inline void +send_IPI_all(int op) +{ + int i; + + for (i = 0; i < smp_num_cpus; i++) + send_IPI_single(__cpu_logical_map[i], op); +} + +static inline void +send_IPI_self(int op) +{ + send_IPI_single(smp_processor_id(), op); +} + +void +smp_send_reschedule(int cpu) +{ + send_IPI_single(cpu, IPI_RESCHEDULE); +} + +void +smp_send_stop(void) +{ + send_IPI_allbutself(IPI_CPU_STOP); +} + +/* + * Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, keep retrying until ready. + * If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until remote CPUs are nearly ready to execute + * or are or have executed. + */ + +int +smp_call_function (void (*func) (void *info), void *info, int retry, int wait) +{ + struct smp_call_struct data; + long timeout; + static spinlock_t lock = SPIN_LOCK_UNLOCKED; + + data.func = func; + data.info = info; + data.wait = wait; + atomic_set(&data.unstarted_count, smp_num_cpus - 1); + atomic_set(&data.unfinished_count, smp_num_cpus - 1); + + if (retry) { + while (1) { + if (smp_call_function_data) { + schedule (); /* Give a mate a go */ + continue; + } + spin_lock (&lock); + if (smp_call_function_data) { + spin_unlock (&lock); /* Bad luck */ + continue; + } + /* Mine, all mine! */ + break; + } + } + else { + if (smp_call_function_data) + return -EBUSY; + spin_lock (&lock); + if (smp_call_function_data) { + spin_unlock (&lock); + return -EBUSY; + } + } + + smp_call_function_data = &data; + spin_unlock (&lock); + data.func = func; + data.info = info; + atomic_set (&data.unstarted_count, smp_num_cpus - 1); + data.wait = wait; + if (wait) + atomic_set (&data.unfinished_count, smp_num_cpus - 1); + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself(IPI_CALL_FUNC); + + /* Wait for response */ + timeout = jiffies + HZ; + while ( (atomic_read (&data.unstarted_count) > 0) && + time_before (jiffies, timeout) ) + barrier (); + if (atomic_read (&data.unstarted_count) > 0) { + smp_call_function_data = NULL; + return -ETIMEDOUT; + } + if (wait) + while (atomic_read (&data.unfinished_count) > 0) + barrier (); + smp_call_function_data = NULL; + return 0; +} + +/* + * Flush all other CPU's tlb and then mine. Do this with smp_call_function() as we + * want to ensure all TLB's flushed before proceeding. + * + * XXX: Is it OK to use the same ptc.e info on all cpus? + */ +void +smp_flush_tlb_all(void) +{ + smp_call_function((void (*)(void *))__flush_tlb_all, NULL, 1, 1); + __flush_tlb_all(); +} + +/* + * Ideally sets up per-cpu profiling hooks. Doesn't do much now... + */ +static inline void __init +smp_setup_percpu_timer(int cpuid) +{ + cpu_data[cpuid].prof_counter = 1; + cpu_data[cpuid].prof_multiplier = 1; +} + +void +smp_do_timer(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int user = user_mode(regs); + struct cpuinfo_ia64 *data = &cpu_data[cpu]; + + extern void update_one_process(struct task_struct *, unsigned long, unsigned long, + unsigned long, int); + if (!--data->prof_counter) { + irq_enter(cpu, TIMER_IRQ); + + update_one_process(current, 1, user, !user, cpu); + if (current->pid) { + if (--current->counter < 0) { + current->counter = 0; + current->need_resched = 1; + } + + if (user) { + if (current->priority < DEF_PRIORITY) { + kstat.cpu_nice++; + kstat.per_cpu_nice[cpu]++; + } else { + kstat.cpu_user++; + kstat.per_cpu_user[cpu]++; + } + } else { + kstat.cpu_system++; + kstat.per_cpu_system[cpu]++; + } + } + + data->prof_counter = data->prof_multiplier; + irq_exit(cpu, TIMER_IRQ); + } +} + + +/* + * Called by both boot and secondaries to move global data into + * per-processor storage. + */ +static inline void __init +smp_store_cpu_info(int cpuid) +{ + struct cpuinfo_ia64 *c = &cpu_data[cpuid]; + + identify_cpu(c); +} + +/* + * SAL shoves the AP's here when we start them. Physical mode, no kernel TR, + * no RRs set, better than even chance that psr is bogus. Fix all that and + * call _start. In effect, pretend to be lilo. + * + * Stolen from lilo_start.c. Thanks David! + */ +void +start_ap(void) +{ + unsigned long flags; + + /* + * Install a translation register that identity maps the + * kernel's 256MB page(s). + */ + ia64_clear_ic(flags); + ia64_set_rr( 0, (0x1000 << 8) | (_PAGE_SIZE_1M << 2)); + ia64_set_rr(PAGE_OFFSET, (ia64_rid(0, PAGE_OFFSET) << 8) | (_PAGE_SIZE_256M << 2)); + ia64_itr(0x3, 1, PAGE_OFFSET, + pte_val(mk_pte_phys(0, __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RWX))), + _PAGE_SIZE_256M); + + flags = (IA64_PSR_IT | IA64_PSR_IC | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | + IA64_PSR_BN); + + asm volatile ("movl r8 = 1f\n" + ";;\n" + "mov cr.ipsr=%0\n" + "mov cr.iip=r8\n" + "mov cr.ifs=r0\n" + ";;\n" + "rfi;;" + "1:\n" + "movl r1 = __gp" :: "r"(flags) : "r8"); + _start(); +} + + +/* + * AP's start using C here. + */ +void __init +smp_callin(void) +{ + extern void ia64_rid_init(void); + extern void ia64_init_itm(void); + extern void ia64_cpu_local_tick(void); + + ia64_set_dcr(IA64_DCR_DR | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_PP); + ia64_set_fpu_owner(0); + ia64_rid_init(); /* initialize region ids */ + + cpu_init(); + __flush_tlb_all(); + + smp_store_cpu_info(smp_processor_id()); + smp_setup_percpu_timer(smp_processor_id()); + + while (!smp_threads_ready) + mb(); + + normal_xtp(); + + /* setup the CPU local timer tick */ + ia64_cpu_local_tick(); + + /* Disable all local interrupts */ + ia64_set_lrr0(0, 1); + ia64_set_lrr1(0, 1); + + __sti(); /* Interrupts have been off till now. */ + cpu_idle(NULL); +} + +/* + * Create the idle task for a new AP. DO NOT use kernel_thread() because + * that could end up calling schedule() in the ia64_leave_kernel exit + * path in which case the new idle task could get scheduled before we + * had a chance to remove it from the run-queue... + */ +static int __init +fork_by_hand(void) +{ + /* + * Don't care about the usp and regs settings since we'll never + * reschedule the forked task. + */ + return do_fork(CLONE_VM|CLONE_PID, 0, 0); +} + +/* + * Bring one cpu online. + * + * NB: cpuid is the CPU BUS-LOCAL ID, not the entire SAPIC ID. See asm/smp.h. + */ +static int __init +smp_boot_one_cpu(int cpuid, int cpunum) +{ + struct task_struct *idle; + long timeout; + + /* + * Create an idle task for this CPU. Note that the address we + * give to kernel_thread is irrelevant -- it's going to start + * where OS_BOOT_RENDEVZ vector in SAL says to start. But + * this gets all the other task-y sort of data structures set + * up like we wish. We need to pull the just created idle task + * off the run queue and stuff it into the init_tasks[] array. + * Sheesh . . . + */ + if (fork_by_hand() < 0) + panic("failed fork for CPU %d", cpuid); + /* + * We remove it from the pidhash and the runqueue + * once we got the process: + */ + idle = init_task.prev_task; + if (!idle) + panic("No idle process for CPU %d", cpuid); + init_tasks[cpunum] = idle; + del_from_runqueue(idle); + unhash_process(idle); + + /* Schedule the first task manually. */ + idle->processor = cpuid; + idle->has_cpu = 1; + + /* Let _start know what logical CPU we're booting (offset into init_tasks[] */ + cpu_now_booting = cpunum; + + /* Kick the AP in the butt */ + send_IPI(cpuid, ap_wakeup_vector); + ia64_srlz_i(); + mb(); + + /* + * OK, wait a bit for that CPU to finish staggering about. smp_callin() will + * call cpu_init() which will set a bit for this AP. When that bit flips, the AP + * is waiting for smp_threads_ready to be 1 and we can move on. + */ + for (timeout = 0; timeout < 100000; timeout++) { + if (test_bit(cpuid, &cpu_initialized)) + goto alive; + udelay(10); + barrier(); + } + + printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid); + return -1; + +alive: + /* Remember the AP data */ + cpu_number_map[cpuid] = cpunum; +#ifdef CONFIG_KDB + cpu_online_map |= (1<processor = bootstrap_processor; + + /* Mark BSP booted and get active_mm context */ + cpu_init(); + + /* reset XTP for interrupt routing */ + normal_xtp(); + + /* And generate an entry in cpu_data */ + smp_store_cpu_info(bootstrap_processor); +#if 0 + smp_tune_scheduling(); +#endif + smp_setup_percpu_timer(bootstrap_processor); + + init_idle(); + + /* Nothing to do when told not to. */ + if (max_cpus == 0) { + printk(KERN_INFO "SMP mode deactivated.\n"); + return; + } + + if (acpi_cpus > 1) { + printk(KERN_INFO "SMP: starting up secondaries.\n"); + + for (i = 0; i < NR_CPUS; i++) { + if (acpi_apic_map[i] == -1 || + acpi_apic_map[i] == bootstrap_processor << 8) /* XXX Fix me Walt */ + continue; + + /* + * IA64 SAPIC ID's are 16-bits. See asm/smp.h for more info + */ + sapic_id = acpi_apic_map[i] >> 8; + if (smp_boot_one_cpu(sapic_id, cpu_count)) + continue; + + cpu_count++; /* Count good CPUs only... */ + } + } + + if (cpu_count == 1) { + printk(KERN_ERR "SMP: Bootstrap processor only.\n"); + return; + } + + bogosum = 0; + for (i = 0; i < NR_CPUS; i++) { + if (cpu_initialized & (1L << i)) + bogosum += cpu_data[i].loops_per_sec; + } + + printk(KERN_INFO "SMP: Total of %d processors activated " + "(%lu.%02lu BogoMIPS).\n", + cpu_count, (bogosum + 2500) / 500000, + ((bogosum + 2500) / 5000) % 100); + + smp_num_cpus = cpu_count; +} + +/* + * Called from main.c by each AP. + */ +void __init +smp_commence(void) +{ + mb(); +} + +/* + * Not used; part of the i386 bringup + */ +void __init +initialize_secondary(void) +{ +} + +int __init +setup_profiling_timer(unsigned int multiplier) +{ + return -EINVAL; +} + +/* + * Assume that CPU's have been discovered by some platform-dependant + * interface. For SoftSDV/Lion, that would be ACPI. + * + * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP(). + * + * So this just gets the BSP SAPIC ID and print's it out. Dull, huh? + * + * Not anymore. This also registers the AP OS_MC_REDVEZ address with SAL. + */ +void __init +init_smp_config(void) +{ + struct fptr { + unsigned long fp; + unsigned long gp; + } *ap_startup; + long sal_ret; + + /* Grab the BSP ID */ + bootstrap_processor = hard_smp_processor_id(); + + /* Tell SAL where to drop the AP's. */ + ap_startup = (struct fptr *) start_ap; + sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, + __pa(ap_startup->fp), __pa(ap_startup->gp), 0, + 0, 0, 0); + if (sal_ret < 0) { + printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); + printk(" Forcing UP mode\n"); + smp_num_cpus = 1; + } + +} + +#ifdef CONFIG_KDB +void smp_kdb_stop (int all, struct pt_regs* regs) +{ + if (all) + { + printk ("Sending IPI to all on CPU %i\n", smp_processor_id ()); + smp_kdb_wait = 0xffffffff; + clear_bit (smp_processor_id(), &smp_kdb_wait); + send_IPI_allbutself (IPI_KDB_INTERRUPT); + } + else + { + printk ("Sending IPI to self on CPU %i\n", + smp_processor_id ()); + set_bit (smp_processor_id(), &smp_kdb_wait); + clear_bit (__cpu_logical_map[kdb_new_cpu], &smp_kdb_wait); + smp_kdb_interrupt (regs); + } +} + +void smp_kdb_interrupt (struct pt_regs* regs) +{ + printk ("kdb: IPI on CPU %i with mask 0x%08x\n", + smp_processor_id (), smp_kdb_wait); + + /* All CPUs spin here forever */ + while (test_bit (smp_processor_id(), &smp_kdb_wait)); + + /* Enter KDB on CPU selected by KDB on the last CPU */ + if (__cpu_logical_map[kdb_new_cpu] == smp_processor_id ()) + { + kdb (KDB_REASON_SWITCH, 0, regs); + } +} + +#endif + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c --- v2.3.42/linux/arch/ia64/kernel/sys_ia64.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/sys_ia64.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,216 @@ +/* + * This file contains various system calls that have different calling + * conventions on different platforms. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + */ +#include +#include +#include +#include +#include +#include +#include /* doh, must come after sched.h... */ +#include +#include + +asmlinkage long +ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6, + long arg7, long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + extern long sys_getpriority (int, int); + long prio; + + prio = sys_getpriority(which, who); + if (prio >= 0) { + regs->r8 = 0; /* ensure negative priority is not mistaken as error code */ + prio = 20 - prio; + } + return prio; +} + +asmlinkage unsigned long +sys_getpagesize (void) +{ + return PAGE_SIZE; +} + +asmlinkage unsigned long +ia64_shmat (int shmid, void *shmaddr, int shmflg, long arg3, long arg4, long arg5, long arg6, + long arg7, long stack) +{ + extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long raddr; + int retval; + + retval = sys_shmat(shmid, shmaddr, shmflg, &raddr); + if (retval < 0) + return retval; + + regs->r8 = 0; /* ensure negative addresses are not mistaken as an error code */ + return raddr; +} + +asmlinkage unsigned long +ia64_brk (long brk, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6, long arg7, long stack) +{ + extern unsigned long sys_brk (unsigned long brk); + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long retval; + + retval = sys_brk(brk); + + regs->r8 = 0; /* ensure large retval isn't mistaken as error code */ + return retval; +} + +/* + * On IA-64, we return the two file descriptors in ret0 and ret1 (r8 + * and r9) as this is faster than doing a copy_to_user(). + */ +asmlinkage long +sys_pipe (long arg0, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6, long arg7, long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + int fd[2]; + int retval; + + lock_kernel(); + retval = do_pipe(fd); + if (retval) + goto out; + retval = fd[0]; + regs->r9 = fd[1]; + out: + unlock_kernel(); + return retval; +} + +static inline unsigned long +do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff) +{ + struct file *file = 0; + + /* + * A zero mmap always succeeds in Linux, independent of + * whether or not the remaining arguments are valid. + */ + if (PAGE_ALIGN(len) == 0) + return addr; + +#ifdef notyet + /* Don't permit mappings that would cross a region boundary: */ + region_start = IA64_GET_REGION(addr); + region_end = IA64_GET_REGION(addr + len); + if (region_start != region_end) + return -EINVAL; + + <> +#endif + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + return -EBADF; + } + + down(¤t->mm->mmap_sem); + lock_kernel(); + + addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + + unlock_kernel(); + up(¤t->mm->mmap_sem); + + if (file) + fput(file); + return addr; +} + +/* + * mmap2() is like mmap() except that the offset is expressed in units + * of PAGE_SIZE (instead of bytes). This allows to mmap2() (pieces + * of) files that are larger than the address space of the CPU. + */ +asmlinkage unsigned long +sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff, + long arg6, long arg7, long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + + addr = do_mmap2(addr, len, prot, flags, fd, pgoff); + if (!IS_ERR(addr)) + regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */ + return addr; +} + +asmlinkage unsigned long +sys_mmap (unsigned long addr, unsigned long len, int prot, int flags, + int fd, long off, long arg6, long arg7, long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + + addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); + if (!IS_ERR(addr)) + regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */ + return addr; +} + +asmlinkage long +sys_ioperm (unsigned long from, unsigned long num, int on) +{ + printk(KERN_ERR "sys_ioperm(from=%lx, num=%lx, on=%d)\n", from, num, on); + return -EIO; +} + +asmlinkage long +sys_iopl (int level, long arg1, long arg2, long arg3) +{ + lock_kernel(); + printk(KERN_ERR "sys_iopl(level=%d)!\n", level); + unlock_kernel(); + return -ENOSYS; +} + +asmlinkage long +sys_vm86 (long arg0, long arg1, long arg2, long arg3) +{ + lock_kernel(); + printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); + unlock_kernel(); + return -ENOSYS; +} + +asmlinkage long +sys_modify_ldt (long arg0, long arg1, long arg2, long arg3) +{ + lock_kernel(); + printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); + unlock_kernel(); + return -ENOSYS; +} + +#ifndef CONFIG_PCI + +asmlinkage long +sys_pciconfig_read (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, + void *buf) +{ + return -ENOSYS; +} + +asmlinkage long +sys_pciconfig_write (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, + void *buf) +{ + return -ENOSYS; +} + + +#endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c --- v2.3.42/linux/arch/ia64/kernel/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/time.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,290 @@ +/* + * linux/arch/ia64/kernel/time.c + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 Stephane Eranian + * Copyright (C) 1999-2000 David Mosberger + * Copyright (C) 1999 Don Dugger + * Copyright (C) 1999-2000 VA Linux Systems + * Copyright (C) 1999-2000 Walt Drummond + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern rwlock_t xtime_lock; +extern volatile unsigned long lost_ticks; + +#ifdef CONFIG_IA64_DEBUG_IRQ + +unsigned long last_cli_ip; + +#endif + +static struct { + unsigned long delta; + unsigned long next[NR_CPUS]; +} itm; + +static void +do_profile (unsigned long ip) +{ + extern char _stext; + + if (prof_buffer && current->pid) { + ip -= (unsigned long) &_stext; + ip >>= prof_shift; + /* + * Don't ignore out-of-bounds IP values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (ip > prof_len - 1) + ip = prof_len - 1; + + atomic_inc((atomic_t *) &prof_buffer[ip]); + } +} + +/* + * Return the number of micro-seconds that elapsed since the last + * update to jiffy. The xtime_lock must be at least read-locked when + * calling this routine. + */ +static inline unsigned long +gettimeoffset (void) +{ + unsigned long now = ia64_get_itc(); + unsigned long elapsed_cycles, lost; + + elapsed_cycles = now - (itm.next[smp_processor_id()] - itm.delta); + + lost = lost_ticks; + if (lost) + elapsed_cycles += lost*itm.delta; + + return (elapsed_cycles*my_cpu_data.usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; +} + +void +do_settimeofday (struct timeval *tv) +{ + write_lock_irq(&xtime_lock); + { + /* + * This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. Discover what + * correction gettimeofday would have done, and then + * undo it! + */ + tv->tv_usec -= gettimeoffset(); + while (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + } + write_unlock_irq(&xtime_lock); +} + +void +do_gettimeofday (struct timeval *tv) +{ + unsigned long flags, usec, sec; + + read_lock_irqsave(&xtime_lock, flags); + { + usec = gettimeoffset(); + + sec = xtime.tv_sec; + usec += xtime.tv_usec; + } + read_unlock_irqrestore(&xtime_lock, flags); + + while (usec >= 1000000) { + usec -= 1000000; + ++sec; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +static void +timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + static unsigned long last_time; + static unsigned char count; + int cpu = smp_processor_id(); + + /* + * Here we are in the timer irq handler. We have irqs locally + * disabled, but we don't know if the timer_bh is running on + * another CPU. We need to avoid to SMP race by acquiring the + * xtime_lock. + */ + write_lock(&xtime_lock); + while (1) { + /* do kernel PC profiling here. */ + if (!user_mode(regs)) + do_profile(regs->cr_iip); + +#ifdef CONFIG_SMP + smp_do_timer(regs); + if (smp_processor_id() == bootstrap_processor) + do_timer(regs); +#else + do_timer(regs); +#endif + + itm.next[cpu] += itm.delta; + /* + * There is a race condition here: to be on the "safe" + * side, we process timer ticks until itm.next is + * ahead of the itc by at least half the timer + * interval. This should give us enough time to set + * the new itm value without losing a timer tick. + */ + if (time_after(itm.next[cpu], ia64_get_itc() + itm.delta/2)) { + ia64_set_itm(itm.next[cpu]); + break; + } + +#if !(defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_SMP)) + /* + * SoftSDV in SMP mode is _slow_, so we do "loose" ticks, + * but it's really OK... + */ + if (count > 0 && jiffies - last_time > 5*HZ) + count = 0; + if (count++ == 0) { + last_time = jiffies; + printk("Lost clock tick on CPU %d (now=%lx, next=%lx)!!\n", + cpu, ia64_get_itc(), itm.next[cpu]); +# ifdef CONFIG_IA64_DEBUG_IRQ + printk("last_cli_ip=%lx\n", last_cli_ip); +# endif + } +#endif + } + write_unlock(&xtime_lock); +} + +/* + * Encapsulate access to the itm structure for SMP. + */ +void __init +ia64_cpu_local_tick(void) +{ + /* arrange for the cycle counter to generate a timer interrupt: */ + ia64_set_itv(TIMER_IRQ, 0); + ia64_set_itc(0); + itm.next[smp_processor_id()] = ia64_get_itc() + itm.delta; + ia64_set_itm(itm.next[smp_processor_id()]); +} + +void __init +ia64_init_itm (void) +{ + unsigned long platform_base_freq, itc_freq, drift; + struct pal_freq_ratio itc_ratio, proc_ratio; + long status; + + /* + * According to SAL v2.6, we need to use a SAL call to determine the + * platform base frequency and then a PAL call to determine the + * frequency ratio between the ITC and the base frequency. + */ + status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_base_freq, &drift); + if (status != 0) { + printk("SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status)); + } else { + status = ia64_pal_freq_ratios(&proc_ratio, 0, &itc_ratio); + if (status != 0) + printk("PAL_FREQ_RATIOS failed with status=%ld\n", status); + } + if (status != 0) { + /* invent "random" values */ + printk("SAL/PAL failed to obtain frequency info---inventing reasonably values\n"); + platform_base_freq = 100000000; + itc_ratio.num = 3; + itc_ratio.den = 1; + } +#if defined(CONFIG_IA64_LION_HACKS) + /* Our Lion currently returns base freq 104.857MHz, which + ain't right (it really is 100MHz). */ + printk("SAL/PAL returned: base-freq=%lu, itc-ratio=%lu/%lu, proc-ratio=%lu/%lu\n", + platform_base_freq, itc_ratio.num, itc_ratio.den, + proc_ratio.num, proc_ratio.den); + platform_base_freq = 100000000; +#elif 0 && defined(CONFIG_IA64_BIGSUR_HACKS) + /* BigSur with 991020 firmware returned itc-ratio=9/2 and base + freq 75MHz, which wasn't right. The 991119 firmware seems + to return the right values, so this isn't necessary + anymore... */ + printk("SAL/PAL returned: base-freq=%lu, itc-ratio=%lu/%lu, proc-ratio=%lu/%lu\n", + platform_base_freq, itc_ratio.num, itc_ratio.den, + proc_ratio.num, proc_ratio.den); + platform_base_freq = 100000000; + proc_ratio.num = 5; proc_ratio.den = 1; + itc_ratio.num = 5; itc_ratio.den = 1; +#elif defined(CONFIG_IA64_SOFTSDV_HACKS) + platform_base_freq = 10000000; + proc_ratio.num = 4; proc_ratio.den = 1; + itc_ratio.num = 4; itc_ratio.den = 1; +#else + if (platform_base_freq < 40000000) { + printk("Platform base frequency %lu bogus---resetting to 75MHz!\n", + platform_base_freq); + platform_base_freq = 75000000; + } +#endif + if (!proc_ratio.den) + proc_ratio.num = 1; /* avoid division by zero */ + if (!itc_ratio.den) + itc_ratio.num = 1; /* avoid division by zero */ + + itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; + itm.delta = itc_freq / HZ; + printk("timer: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, ITC freq=%lu.%03luMHz\n", + platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, + itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); + + my_cpu_data.proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; + my_cpu_data.itc_freq = itc_freq; + my_cpu_data.cyc_per_usec = itc_freq / 1000000; + my_cpu_data.usec_per_cyc = (1000000UL << IA64_USEC_PER_CYC_SHIFT) / itc_freq; + + /* Setup the CPU local timer tick */ + ia64_cpu_local_tick(); +} + +void __init +time_init (void) +{ + /* + * Request the IRQ _before_ doing anything to cause that + * interrupt to be posted. + */ + if (request_irq(TIMER_IRQ, timer_interrupt, 0, "timer", NULL)) + panic("Could not allocate timer IRQ!"); + + efi_gettimeofday(&xtime); + ia64_init_itm(); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c --- v2.3.42/linux/arch/ia64/kernel/traps.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/traps.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,423 @@ +/* + * Architecture-specific trap handling. + * + * Copyright (C) 1998-2000 Hewlett-Packard Co + * Copyright (C) 1998-2000 David Mosberger-Tang + */ + +/* + * The fpu_fault() handler needs to be able to access and update all + * floating point registers. Those saved in pt_regs can be accessed + * through that structure, but those not saved, will be accessed + * directly. To make this work, we need to ensure that the compiler + * does not end up using a preserved floating point register on its + * own. The following achieves this by declaring preserved registers + * that are not marked as "fixed" as global register variables. + */ +register double f2 asm ("f2"); register double f3 asm ("f3"); +register double f4 asm ("f4"); register double f5 asm ("f5"); + +register long f16 asm ("f16"); register long f17 asm ("f17"); +register long f18 asm ("f18"); register long f19 asm ("f19"); +register long f20 asm ("f20"); register long f21 asm ("f21"); +register long f22 asm ("f22"); register long f23 asm ("f23"); + +register double f24 asm ("f24"); register double f25 asm ("f25"); +register double f26 asm ("f26"); register double f27 asm ("f27"); +register double f28 asm ("f28"); register double f29 asm ("f29"); +register double f30 asm ("f30"); register double f31 asm ("f31"); + +#include +#include +#include +#include + +#ifdef CONFIG_KDB +# include +#endif + +#include +#include + +#include + +static fpswa_interface_t *fpswa_interface; + +void __init +trap_init (void) +{ + printk("fpswa interface at %lx\n", ia64_boot_param.fpswa); + if (ia64_boot_param.fpswa) { +#define OLD_FIRMWARE +#ifdef OLD_FIRMWARE + /* + * HACK to work around broken firmware. This code + * applies the label fixup to the FPSWA interface and + * works both with old and new (fixed) firmware. + */ + unsigned long addr = (unsigned long) __va(ia64_boot_param.fpswa); + unsigned long gp_val = *(unsigned long *)(addr + 8); + + /* go indirect and indexed to get table address */ + addr = gp_val; + gp_val = *(unsigned long *)(addr + 8); + + while (gp_val == *(unsigned long *)(addr + 8)) { + *(unsigned long *)addr |= PAGE_OFFSET; + *(unsigned long *)(addr + 8) |= PAGE_OFFSET; + addr += 16; + } +#endif + /* FPSWA fixup: make the interface pointer a kernel virtual address: */ + fpswa_interface = __va(ia64_boot_param.fpswa); + } +} + +void +die_if_kernel (char *str, struct pt_regs *regs, long err) +{ + if (user_mode(regs)) { +#if 1 + /* XXX for debugging only */ + printk ("!!die_if_kernel: %s(%d): %s %ld\n", + current->comm, current->pid, str, err); + show_regs(regs); +#endif + return; + } + + printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); + +#ifdef CONFIG_KDB + while (1) { + kdb(KDB_REASON_PANIC, 0, regs); + printk("Cant go anywhere from Panic!\n"); + } +#endif + + show_regs(regs); + + if (current->thread.flags & IA64_KERNEL_DEATH) { + printk("die_if_kernel recursion detected.\n"); + sti(); + while (1); + } + current->thread.flags |= IA64_KERNEL_DEATH; + do_exit(SIGSEGV); +} + +void +ia64_bad_break (unsigned long break_num, struct pt_regs *regs) +{ + siginfo_t siginfo; + + /* gdb uses a break number of 0xccccc for debug breakpoints: */ + if (break_num != 0xccccc) + die_if_kernel("Bad break", regs, break_num); + + siginfo.si_signo = SIGTRAP; + siginfo.si_errno = break_num; /* XXX is it legal to abuse si_errno like this? */ + siginfo.si_code = TRAP_BRKPT; + send_sig_info(SIGTRAP, &siginfo, current); +} + +/* + * Unimplemented system calls. This is called only for stuff that + * we're supposed to implement but haven't done so yet. Everything + * else goes to sys_ni_syscall. + */ +asmlinkage long +ia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7, + unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + + printk("\n", regs->r15, arg0, arg1, arg2, arg3); + return -ENOSYS; +} + +/* + * disabled_fp_fault() is called when a user-level process attempts to + * access one of the registers f32..f127 while it doesn't own the + * fp-high register partition. When this happens, we save the current + * fph partition in the task_struct of the fpu-owner (if necessary) + * and then load the fp-high partition of the current task (if + * necessary). + */ +static inline void +disabled_fph_fault (struct pt_regs *regs) +{ + struct task_struct *fpu_owner = ia64_get_fpu_owner(); + + regs->cr_ipsr &= ~(IA64_PSR_DFH | IA64_PSR_MFH); + if (fpu_owner != current) { + ia64_set_fpu_owner(current); + + if (fpu_owner && ia64_psr(ia64_task_regs(fpu_owner))->mfh) { + fpu_owner->thread.flags |= IA64_THREAD_FPH_VALID; + __ia64_save_fpu(fpu_owner->thread.fph); + } + if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { + __ia64_load_fpu(current->thread.fph); + } else { + __ia64_init_fpu(); + } + } +} + +static inline int +fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs, + struct pt_regs *regs) +{ + fp_state_t fp_state; + fpswa_ret_t ret; +#ifdef FPSWA_BUG + struct ia64_fpreg f6_15[10]; +#endif + + if (!fpswa_interface) + return -1; + + memset(&fp_state, 0, sizeof(fp_state_t)); + + /* + * compute fp_state. only FP registers f6 - f11 are used by the + * kernel, so set those bits in the mask and set the low volatile + * pointer to point to these registers. + */ + fp_state.bitmask_low64 = 0xffc0; /* bit6..bit15 */ +#ifndef FPSWA_BUG + fp_state.fp_state_low_volatile = ®s->f6; +#else + f6_15[0] = regs->f6; + f6_15[1] = regs->f7; + f6_15[2] = regs->f8; + f6_15[3] = regs->f9; + __asm__ ("stf.spill %0=f10" : "=m"(f6_15[4])); + __asm__ ("stf.spill %0=f11" : "=m"(f6_15[5])); + __asm__ ("stf.spill %0=f12" : "=m"(f6_15[6])); + __asm__ ("stf.spill %0=f13" : "=m"(f6_15[7])); + __asm__ ("stf.spill %0=f14" : "=m"(f6_15[8])); + __asm__ ("stf.spill %0=f15" : "=m"(f6_15[9])); + fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15; +#endif + /* + * unsigned long (*EFI_FPSWA) ( + * unsigned long trap_type, + * void *Bundle, + * unsigned long *pipsr, + * unsigned long *pfsr, + * unsigned long *pisr, + * unsigned long *ppreds, + * unsigned long *pifs, + * void *fp_state); + */ + ret = (*fpswa_interface->fpswa)((unsigned long) fp_fault, bundle, + (unsigned long *) ipsr, (unsigned long *) fpsr, + (unsigned long *) isr, (unsigned long *) pr, + (unsigned long *) ifs, &fp_state); +#ifdef FPSWA_BUG + __asm__ ("ldf.fill f10=%0" :: "m"(f6_15[4])); + __asm__ ("ldf.fill f11=%0" :: "m"(f6_15[5])); + __asm__ ("ldf.fill f12=%0" :: "m"(f6_15[6])); + __asm__ ("ldf.fill f13=%0" :: "m"(f6_15[7])); + __asm__ ("ldf.fill f14=%0" :: "m"(f6_15[8])); + __asm__ ("ldf.fill f15=%0" :: "m"(f6_15[9])); + regs->f6 = f6_15[0]; + regs->f7 = f6_15[1]; + regs->f8 = f6_15[2]; + regs->f9 = f6_15[3]; +#endif + return ret.status; +} + +/* + * Handle floating-point assist faults and traps. + */ +static int +handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) +{ + long exception, bundle[2]; + unsigned long fault_ip; + static int fpu_swa_count = 0; + static unsigned long last_time; + + fault_ip = regs->cr_iip; + if (!fp_fault && (ia64_psr(regs)->ri == 0)) + fault_ip -= 16; + if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle))) + return -1; + + if (fpu_swa_count > 5 && jiffies - last_time > 5*HZ) + fpu_swa_count = 0; + if (++fpu_swa_count < 5) { + last_time = jiffies; + printk("%s(%d): floating-point assist fault at ip %016lx\n", + current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri); + } + + exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, + ®s->cr_ifs, regs); + if (fp_fault) { + if (exception == 0) { + /* emulation was successful */ + ia64_increment_ip(regs); + } else if (exception == -1) { + printk("handle_fpu_swa: fp_emulate() returned -1\n"); + return -2; + } else { + /* is next instruction a trap? */ + if (exception & 2) { + ia64_increment_ip(regs); + } + return -1; + } + } else { + if (exception == -1) { + printk("handle_fpu_swa: fp_emulate() returned -1\n"); + return -2; + } else if (exception != 0) { + /* raise exception */ + return -1; + } + } + return 0; +} + +void +ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, + unsigned long iim, unsigned long itir, unsigned long arg5, + unsigned long arg6, unsigned long arg7, unsigned long stack) +{ + struct pt_regs *regs = (struct pt_regs *) &stack; + unsigned long code, error = isr; + struct siginfo siginfo; + char buf[128]; + int result; + static const char *reason[] = { + "IA-64 Illegal Operation fault", + "IA-64 Privileged Operation fault", + "IA-64 Privileged Register fault", + "IA-64 Reserved Register/Field fault", + "Disabled Instruction Set Transition fault", + "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", + "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", + "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" + }; + +#if 0 + /* this is for minimal trust debugging; yeah this kind of stuff is useful at times... */ + + if (vector != 25) { + static unsigned long last_time; + static char count; + unsigned long n = vector; + char buf[32], *cp; + + if (count > 5 && jiffies - last_time > 5*HZ) + count = 0; + + if (count++ < 5) { + last_time = jiffies; + cp = buf + sizeof(buf); + *--cp = '\0'; + while (n) { + *--cp = "0123456789abcdef"[n & 0xf]; + n >>= 4; + } + printk("<0x%s>", cp); + } + } +#endif + + switch (vector) { + case 24: /* General Exception */ + code = (isr >> 4) & 0xf; + sprintf(buf, "General Exception: %s%s", reason[code], + (code == 3) ? ((isr & (1UL << 37)) + ? " (RSE access)" : " (data access)") : ""); +#ifndef CONFIG_ITANIUM_ASTEP_SPECIFIC + if (code == 8) { +# ifdef CONFIG_IA64_PRINT_HAZARDS + printk("%016lx:possible hazard, pr = %016lx\n", regs->cr_iip, regs->pr); +# endif + return; + } +#endif + break; + + case 25: /* Disabled FP-Register */ + if (isr & 2) { + disabled_fph_fault(regs); + return; + } + sprintf(buf, "Disabled FPL fault---not supposed to happen!"); + break; + + case 29: /* Debug */ + case 35: /* Taken Branch Trap */ + case 36: /* Single Step Trap */ + switch (vector) { + case 29: siginfo.si_code = TRAP_BRKPT; break; + case 35: siginfo.si_code = TRAP_BRANCH; break; + case 36: siginfo.si_code = TRAP_TRACE; break; + } + siginfo.si_signo = SIGTRAP; + siginfo.si_errno = 0; + force_sig_info(SIGTRAP, &siginfo, current); + return; + + case 30: /* Unaligned fault */ + sprintf(buf, "Unaligned access in kernel mode---don't do this!"); + break; + + case 32: /* fp fault */ + case 33: /* fp trap */ + result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); + if (result < 0) { + siginfo.si_signo = SIGFPE; + siginfo.si_errno = 0; + siginfo.si_code = 0; /* XXX fix me */ + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + send_sig_info(SIGFPE, &siginfo, current); + if (result == -1) + send_sig_info(SIGFPE, &siginfo, current); + else + force_sig(SIGFPE, current); + } + return; + + case 34: /* Unimplemented Instruction Address Trap */ + if (user_mode(regs)) { + printk("Woah! Unimplemented Instruction Address Trap!\n"); + siginfo.si_code = ILL_BADIADDR; + siginfo.si_signo = SIGILL; + siginfo.si_errno = 0; + force_sig_info(SIGILL, &siginfo, current); + return; + } + sprintf(buf, "Unimplemented Instruction Address fault"); + break; + + case 45: + printk("Unexpected IA-32 exception\n"); + force_sig(SIGSEGV, current); + return; + + case 46: + printk("Unexpected IA-32 intercept trap\n"); + force_sig(SIGSEGV, current); + return; + + case 47: + sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16); + break; + + default: + sprintf(buf, "Fault %lu", vector); + break; + } + die_if_kernel(buf, regs, error); + force_sig(SIGILL, current); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c --- v2.3.42/linux/arch/ia64/kernel/unaligned.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/unaligned.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,1554 @@ +/* + * Architecture-specific unaligned trap handling. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + */ +#include +#include +#include +#include +#include +#include +#include + +extern void die_if_kernel(char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn)); + +#undef DEBUG_UNALIGNED_TRAP + +#ifdef DEBUG_UNALIGNED_TRAP +#define DPRINT(a) { printk("%s, line %d: ", __FUNCTION__, __LINE__); printk a;} +#else +#define DPRINT(a) +#endif + +#define IA64_FIRST_STACKED_GR 32 +#define IA64_FIRST_ROTATING_FR 32 +#define SIGN_EXT9 __IA64_UL(0xffffffffffffff00) + +/* + * For M-unit: + * + * opcode | m | x6 | + * --------|------|---------| + * [40-37] | [36] | [35:30] | + * --------|------|---------| + * 4 | 1 | 6 | = 11 bits + * -------------------------- + * However bits [31:30] are not directly useful to distinguish between + * load/store so we can use [35:32] instead, which gives the following + * mask ([40:32]) using 9 bits. The 'e' comes from the fact that we defer + * checking the m-bit until later in the load/store emulation. + */ +#define IA64_OPCODE_MASK 0x1ef00000000 + +/* + * Table C-28 Integer Load/Store + * + * We ignore [35:32]= 0x6, 0x7, 0xE, 0xF + * + * ld8.fill, st8.fill MUST be aligned because the RNATs are based on + * the address (bits [8:3]), so we must failed. + */ +#define LD_OP 0x08000000000 +#define LDS_OP 0x08100000000 +#define LDA_OP 0x08200000000 +#define LDSA_OP 0x08300000000 +#define LDBIAS_OP 0x08400000000 +#define LDACQ_OP 0x08500000000 +/* 0x086, 0x087 are not relevant */ +#define LDCCLR_OP 0x08800000000 +#define LDCNC_OP 0x08900000000 +#define LDCCLRACQ_OP 0x08a00000000 +#define ST_OP 0x08c00000000 +#define STREL_OP 0x08d00000000 +/* 0x08e,0x8f are not relevant */ + +/* + * Table C-29 Integer Load +Reg + * + * we use the ld->m (bit [36:36]) field to determine whether or not we have + * a load/store of this form. + */ + +/* + * Table C-30 Integer Load/Store +Imm + * + * We ignore [35:32]= 0x6, 0x7, 0xE, 0xF + * + * ld8.fill, st8.fill must be aligned because the Nat register are based on + * the address, so we must fail and the program must be fixed. + */ +#define LD_IMM_OP 0x0a000000000 +#define LDS_IMM_OP 0x0a100000000 +#define LDA_IMM_OP 0x0a200000000 +#define LDSA_IMM_OP 0x0a300000000 +#define LDBIAS_IMM_OP 0x0a400000000 +#define LDACQ_IMM_OP 0x0a500000000 +/* 0x0a6, 0xa7 are not relevant */ +#define LDCCLR_IMM_OP 0x0a800000000 +#define LDCNC_IMM_OP 0x0a900000000 +#define LDCCLRACQ_IMM_OP 0x0aa00000000 +#define ST_IMM_OP 0x0ac00000000 +#define STREL_IMM_OP 0x0ad00000000 +/* 0x0ae,0xaf are not relevant */ + +/* + * Table C-32 Floating-point Load/Store + */ +#define LDF_OP 0x0c000000000 +#define LDFS_OP 0x0c100000000 +#define LDFA_OP 0x0c200000000 +#define LDFSA_OP 0x0c300000000 +/* 0x0c6 is irrelevant */ +#define LDFCCLR_OP 0x0c800000000 +#define LDFCNC_OP 0x0c900000000 +/* 0x0cb is irrelevant */ +#define STF_OP 0x0cc00000000 + +/* + * Table C-33 Floating-point Load +Reg + * + * we use the ld->m (bit [36:36]) field to determine whether or not we have + * a load/store of this form. + */ + +/* + * Table C-34 Floating-point Load/Store +Imm + */ +#define LDF_IMM_OP 0x0e000000000 +#define LDFS_IMM_OP 0x0e100000000 +#define LDFA_IMM_OP 0x0e200000000 +#define LDFSA_IMM_OP 0x0e300000000 +/* 0x0e6 is irrelevant */ +#define LDFCCLR_IMM_OP 0x0e800000000 +#define LDFCNC_IMM_OP 0x0e900000000 +#define STF_IMM_OP 0x0ec00000000 + +typedef struct { + unsigned long qp:6; /* [0:5] */ + unsigned long r1:7; /* [6:12] */ + unsigned long imm:7; /* [13:19] */ + unsigned long r3:7; /* [20:26] */ + unsigned long x:1; /* [27:27] */ + unsigned long hint:2; /* [28:29] */ + unsigned long x6_sz:2; /* [30:31] */ + unsigned long x6_op:4; /* [32:35], x6 = x6_sz|x6_op */ + unsigned long m:1; /* [36:36] */ + unsigned long op:4; /* [37:40] */ + unsigned long pad:23; /* [41:63] */ +} load_store_t; + + +typedef enum { + UPD_IMMEDIATE, /* ldXZ r1=[r3],imm(9) */ + UPD_REG /* ldXZ r1=[r3],r2 */ +} update_t; + +/* + * We use tables to keep track of the offsets of registers in the saved state. + * This way we save having big switch/case statements. + * + * We use bit 0 to indicate switch_stack or pt_regs. + * The offset is simply shifted by 1 bit. + * A 2-byte value should be enough to hold any kind of offset + * + * In case the calling convention changes (and thus pt_regs/switch_stack) + * simply use RSW instead of RPT or vice-versa. + */ + +#define RPO(x) ((size_t) &((struct pt_regs *)0)->x) +#define RSO(x) ((size_t) &((struct switch_stack *)0)->x) + +#define RPT(x) (RPO(x) << 1) +#define RSW(x) (1| RSO(x)<<1) + +#define GR_OFFS(x) (gr_info[x]>>1) +#define GR_IN_SW(x) (gr_info[x] & 0x1) + +#define FR_OFFS(x) (fr_info[x]>>1) +#define FR_IN_SW(x) (fr_info[x] & 0x1) + +static u16 gr_info[32]={ + 0, /* r0 is read-only : WE SHOULD NEVER GET THIS */ + + RPT(r1), RPT(r2), RPT(r3), + + RSW(r4), RSW(r5), RSW(r6), RSW(r7), + + RPT(r8), RPT(r9), RPT(r10), RPT(r11), + RPT(r12), RPT(r13), RPT(r14), RPT(r15), + + RPT(r16), RPT(r17), RPT(r18), RPT(r19), + RPT(r20), RPT(r21), RPT(r22), RPT(r23), + RPT(r24), RPT(r25), RPT(r26), RPT(r27), + RPT(r28), RPT(r29), RPT(r30), RPT(r31) +}; + +static u16 fr_info[32]={ + 0, /* constant : WE SHOULD NEVER GET THIS */ + 0, /* constant : WE SHOULD NEVER GET THIS */ + + RSW(f2), RSW(f3), RSW(f4), RSW(f5), + + RPT(f6), RPT(f7), RPT(f8), RPT(f9), + + RSW(f10), RSW(f11), RSW(f12), RSW(f13), RSW(f14), + RSW(f15), RSW(f16), RSW(f17), RSW(f18), RSW(f19), + RSW(f20), RSW(f21), RSW(f22), RSW(f23), RSW(f24), + RSW(f25), RSW(f26), RSW(f27), RSW(f28), RSW(f29), + RSW(f30), RSW(f31) +}; + +/* Invalidate ALAT entry for integer register REGNO. */ +static void +invala_gr (int regno) +{ +# define F(reg) case reg: __asm__ __volatile__ ("invala.e r%0" :: "i"(reg)); break + + switch (regno) { + F( 0); F( 1); F( 2); F( 3); F( 4); F( 5); F( 6); F( 7); + F( 8); F( 9); F( 10); F( 11); F( 12); F( 13); F( 14); F( 15); + F( 16); F( 17); F( 18); F( 19); F( 20); F( 21); F( 22); F( 23); + F( 24); F( 25); F( 26); F( 27); F( 28); F( 29); F( 30); F( 31); + F( 32); F( 33); F( 34); F( 35); F( 36); F( 37); F( 38); F( 39); + F( 40); F( 41); F( 42); F( 43); F( 44); F( 45); F( 46); F( 47); + F( 48); F( 49); F( 50); F( 51); F( 52); F( 53); F( 54); F( 55); + F( 56); F( 57); F( 58); F( 59); F( 60); F( 61); F( 62); F( 63); + F( 64); F( 65); F( 66); F( 67); F( 68); F( 69); F( 70); F( 71); + F( 72); F( 73); F( 74); F( 75); F( 76); F( 77); F( 78); F( 79); + F( 80); F( 81); F( 82); F( 83); F( 84); F( 85); F( 86); F( 87); + F( 88); F( 89); F( 90); F( 91); F( 92); F( 93); F( 94); F( 95); + F( 96); F( 97); F( 98); F( 99); F(100); F(101); F(102); F(103); + F(104); F(105); F(106); F(107); F(108); F(109); F(110); F(111); + F(112); F(113); F(114); F(115); F(116); F(117); F(118); F(119); + F(120); F(121); F(122); F(123); F(124); F(125); F(126); F(127); + } +# undef F +} + +/* Invalidate ALAT entry for floating-point register REGNO. */ +static void +invala_fr (int regno) +{ +# define F(reg) case reg: __asm__ __volatile__ ("invala.e f%0" :: "i"(reg)); break + + switch (regno) { + F( 0); F( 1); F( 2); F( 3); F( 4); F( 5); F( 6); F( 7); + F( 8); F( 9); F( 10); F( 11); F( 12); F( 13); F( 14); F( 15); + F( 16); F( 17); F( 18); F( 19); F( 20); F( 21); F( 22); F( 23); + F( 24); F( 25); F( 26); F( 27); F( 28); F( 29); F( 30); F( 31); + F( 32); F( 33); F( 34); F( 35); F( 36); F( 37); F( 38); F( 39); + F( 40); F( 41); F( 42); F( 43); F( 44); F( 45); F( 46); F( 47); + F( 48); F( 49); F( 50); F( 51); F( 52); F( 53); F( 54); F( 55); + F( 56); F( 57); F( 58); F( 59); F( 60); F( 61); F( 62); F( 63); + F( 64); F( 65); F( 66); F( 67); F( 68); F( 69); F( 70); F( 71); + F( 72); F( 73); F( 74); F( 75); F( 76); F( 77); F( 78); F( 79); + F( 80); F( 81); F( 82); F( 83); F( 84); F( 85); F( 86); F( 87); + F( 88); F( 89); F( 90); F( 91); F( 92); F( 93); F( 94); F( 95); + F( 96); F( 97); F( 98); F( 99); F(100); F(101); F(102); F(103); + F(104); F(105); F(106); F(107); F(108); F(109); F(110); F(111); + F(112); F(113); F(114); F(115); F(116); F(117); F(118); F(119); + F(120); F(121); F(122); F(123); F(124); F(125); F(126); F(127); + } +# undef F +} + +static void +set_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long val, int nat) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + unsigned long *kbs = ((unsigned long *)current) + IA64_RBS_OFFSET/8; + unsigned long on_kbs; + unsigned long *bsp, *bspstore, *addr, *ubs_end, *slot; + unsigned long rnats; + long nlocals; + + /* + * cr_ifs=[rv:ifm], ifm=[....:sof(6)] + * nlocal=number of locals (in+loc) register of the faulting function + */ + nlocals = (regs->cr_ifs) & 0x7f; + + DPRINT(("sw.bsptore=%lx pt.bspstore=%lx\n", sw->ar_bspstore, regs->ar_bspstore)); + DPRINT(("cr.ifs=%lx sof=%ld sol=%ld\n", + regs->cr_ifs, regs->cr_ifs &0x7f, (regs->cr_ifs>>7)&0x7f)); + + on_kbs = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore); + bspstore = (unsigned long *)regs->ar_bspstore; + + DPRINT(("rse_slot_num=0x%lx\n",ia64_rse_slot_num((unsigned long *)sw->ar_bspstore))); + DPRINT(("kbs=%p nlocals=%ld\n", kbs, nlocals)); + DPRINT(("bspstore next rnat slot %p\n", + ia64_rse_rnat_addr((unsigned long *)sw->ar_bspstore))); + DPRINT(("on_kbs=%ld rnats=%ld\n", + on_kbs, ((sw->ar_bspstore-(unsigned long)kbs)>>3) - on_kbs)); + + /* + * See get_rse_reg() for an explanation on the following instructions + */ + ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); + bsp = ia64_rse_skip_regs(ubs_end, -nlocals); + addr = slot = ia64_rse_skip_regs(bsp, r1 - 32); + + DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n", + ubs_end, bsp, addr, ia64_rse_slot_num(addr))); + + ia64_poke(regs, current, (unsigned long)addr, val); + + /* + * addr will now contain the address of the RNAT for the register + */ + addr = ia64_rse_rnat_addr(addr); + + ia64_peek(regs, current, (unsigned long)addr, &rnats); + DPRINT(("rnat @%p = 0x%lx nat=%d rnatval=%lx\n", + addr, rnats, nat, rnats &ia64_rse_slot_num(slot))); + + if ( nat ) { + rnats |= __IA64_UL(1) << ia64_rse_slot_num(slot); + } else { + rnats &= ~(__IA64_UL(1) << ia64_rse_slot_num(slot)); + } + ia64_poke(regs, current, (unsigned long)addr, rnats); + + DPRINT(("rnat changed to @%p = 0x%lx\n", addr, rnats)); +} + + +static void +get_rse_reg(struct pt_regs *regs, unsigned long r1, unsigned long *val, int *nat) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + unsigned long *kbs = (unsigned long *)current + IA64_RBS_OFFSET/8; + unsigned long on_kbs; + long nlocals; + unsigned long *bsp, *addr, *ubs_end, *slot, *bspstore; + unsigned long rnats; + + /* + * cr_ifs=[rv:ifm], ifm=[....:sof(6)] + * nlocals=number of local registers in the faulting function + */ + nlocals = (regs->cr_ifs) & 0x7f; + + /* + * save_switch_stack does a flushrs and saves bspstore. + * on_kbs = actual number of registers saved on kernel backing store + * (taking into accound potential RNATs) + * + * Note that this number can be greater than nlocals if the dirty + * parititions included more than one stack frame at the time we + * switched to KBS + */ + on_kbs = ia64_rse_num_regs(kbs, (unsigned long *)sw->ar_bspstore); + bspstore = (unsigned long *)regs->ar_bspstore; + + /* + * To simplify the logic, we calculate everything as if there was only + * one backing store i.e., the user one (UBS). We let it to peek/poke + * to figure out whether the register we're looking for really is + * on the UBS or on KBS. + * + * regs->ar_bsptore = address of last register saved on UBS (before switch) + * + * ubs_end = virtual end of the UBS (if everything had been spilled there) + * + * We know that ubs_end is the point where the last register on the + * stack frame we're interested in as been saved. So we need to walk + * our way backward to figure out what the BSP "was" for that frame, + * this will give us the location of r32. + * + * bsp = "virtual UBS" address of r32 for our frame + * + * Finally, get compute the address of the register we're looking for + * using bsp as our base (move up again). + * + * Please note that in our case, we know that the register is necessarily + * on the KBS because we are only interested in the current frame at the moment + * we got the exception i.e., bsp is not changed until we switch to KBS. + */ + ubs_end = ia64_rse_skip_regs(bspstore, on_kbs); + bsp = ia64_rse_skip_regs(ubs_end, -nlocals); + addr = slot = ia64_rse_skip_regs(bsp, r1 - 32); + + DPRINT(("ubs_end=%p bsp=%p addr=%p slot=0x%lx\n", + ubs_end, bsp, addr, ia64_rse_slot_num(addr))); + + ia64_peek(regs, current, (unsigned long)addr, val); + + /* + * addr will now contain the address of the RNAT for the register + */ + addr = ia64_rse_rnat_addr(addr); + + ia64_peek(regs, current, (unsigned long)addr, &rnats); + DPRINT(("rnat @%p = 0x%lx\n", addr, rnats)); + + if ( nat ) *nat = rnats >> ia64_rse_slot_num(slot) & 0x1; +} + + +static void +setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs -1; + unsigned long addr; + unsigned long bitmask; + unsigned long *unat; + + + /* + * First takes care of stacked registers + */ + if ( regnum >= IA64_FIRST_STACKED_GR ) { + set_rse_reg(regs, regnum, val, nat); + return; + } + + /* + * Using r0 as a target raises a General Exception fault which has + * higher priority than the Unaligned Reference fault. + */ + + /* + * Now look at registers in [0-31] range and init correct UNAT + */ + if ( GR_IN_SW(regnum) ) { + addr = (unsigned long)sw; + unat = &sw->ar_unat; + } else { + addr = (unsigned long)regs; + unat = &sw->caller_unat; + } + DPRINT(("tmp_base=%lx switch_stack=%s offset=%d\n", + addr, unat==&sw->ar_unat ? "yes":"no", GR_OFFS(regnum))); + /* + * add offset from base of struct + * and do it ! + */ + addr += GR_OFFS(regnum); + + *(unsigned long *)addr = val; + + /* + * We need to clear the corresponding UNAT bit to fully emulate the load + * UNAT bit_pos = GR[r3]{8:3} form EAS-2.4 + */ + bitmask = __IA64_UL(1) << (addr >> 3 & 0x3f); + DPRINT(("*0x%lx=0x%lx NaT=%d prev_unat @%p=%lx\n", addr, val, nat, unat, *unat)); + if ( nat ) { + *unat |= bitmask; + } else { + *unat &= ~bitmask; + } + DPRINT(("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, unat,*unat)); +} + +#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR) + +static void +setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + unsigned long addr; + + /* + * From EAS-2.5: FPDisableFault has higher priority than + * Unaligned Fault. Thus, when we get here, we know the partition is + * enabled. + * + * The registers [32-127] are ususally saved in the tss. When get here, + * they are NECESSARY live because they are only saved explicitely. + * We have 3 ways of updating the values: force a save of the range + * in tss, use a gigantic switch/case statement or generate code on the + * fly to store to the right register. + * For now, we are using the (slow) save/restore way. + */ + if ( regnum >= IA64_FIRST_ROTATING_FR ) { + /* + * force a save of [32-127] to tss + * we use the __() form to avoid fiddling with the dfh bit + */ + __ia64_save_fpu(¤t->thread.fph[0]); + + current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval; + + __ia64_load_fpu(¤t->thread.fph[0]); + + /* + * mark the high partition as being used now + * + * This is REQUIRED because the disabled_fph_fault() does + * not set it, it's relying on the faulting instruction to + * do it. In our case the faulty instruction never gets executed + * completely, so we need to toggle the bit. + */ + regs->cr_ipsr |= IA64_PSR_MFH; + } else { + /* + * pt_regs or switch_stack ? + */ + if ( FR_IN_SW(regnum) ) { + addr = (unsigned long)sw; + } else { + addr = (unsigned long)regs; + } + + DPRINT(("tmp_base=%lx offset=%d\n", addr, FR_OFFS(regnum))); + + addr += FR_OFFS(regnum); + *(struct ia64_fpreg *)addr = *fpval; + + /* + * mark the low partition as being used now + * + * It is highly unlikely that this bit is not already set, but + * let's do it for safety. + */ + regs->cr_ipsr |= IA64_PSR_MFL; + + } +} + +/* + * Those 2 inline functions generate the spilled versions of the constant floating point + * registers which can be used with stfX + */ +static inline void +float_spill_f0(struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("stf.spill [%0]=f0" :: "r"(final) : "memory"); +} + +static inline void +float_spill_f1(struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("stf.spill [%0]=f1" :: "r"(final) : "memory"); +} + +static void +getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs -1; + unsigned long addr; + + /* + * From EAS-2.5: FPDisableFault has higher priority than + * Unaligned Fault. Thus, when we get here, we know the partition is + * enabled. + * + * When regnum > 31, the register is still live and + * we need to force a save to the tss to get access to it. + * See discussion in setfpreg() for reasons and other ways of doing this. + */ + if ( regnum >= IA64_FIRST_ROTATING_FR ) { + + /* + * force a save of [32-127] to tss + * we use the__ia64_save_fpu() form to avoid fiddling with + * the dfh bit. + */ + __ia64_save_fpu(¤t->thread.fph[0]); + + *fpval = current->thread.fph[IA64_FPH_OFFS(regnum)]; + } else { + /* + * f0 = 0.0, f1= 1.0. Those registers are constant and are thus + * not saved, we must generate their spilled form on the fly + */ + switch(regnum) { + case 0: + float_spill_f0(fpval); + break; + case 1: + float_spill_f1(fpval); + break; + default: + /* + * pt_regs or switch_stack ? + */ + addr = FR_IN_SW(regnum) ? (unsigned long)sw + : (unsigned long)regs; + + DPRINT(("is_sw=%d tmp_base=%lx offset=0x%x\n", + FR_IN_SW(regnum), addr, FR_OFFS(regnum))); + + addr += FR_OFFS(regnum); + *fpval = *(struct ia64_fpreg *)addr; + } + } +} + + +static void +getreg(unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs -1; + unsigned long addr, *unat; + + if ( regnum >= IA64_FIRST_STACKED_GR ) { + get_rse_reg(regs, regnum, val, nat); + return; + } + + /* + * take care of r0 (read-only always evaluate to 0) + */ + if ( regnum == 0 ) { + *val = 0; + *nat = 0; + return; + } + + /* + * Now look at registers in [0-31] range and init correct UNAT + */ + if ( GR_IN_SW(regnum) ) { + addr = (unsigned long)sw; + unat = &sw->ar_unat; + } else { + addr = (unsigned long)regs; + unat = &sw->caller_unat; + } + + DPRINT(("addr_base=%lx offset=0x%x\n", addr, GR_OFFS(regnum))); + + addr += GR_OFFS(regnum); + + *val = *(unsigned long *)addr; + + /* + * do it only when requested + */ + if ( nat ) *nat = (*unat >> (addr >> 3 & 0x3f)) & 0x1UL; +} + +static void +emulate_load_updates(update_t type, load_store_t *ld, struct pt_regs *regs, unsigned long ifa) +{ + /* + * IMPORTANT: + * Given the way we handle unaligned speculative loads, we should + * not get to this point in the code but we keep this sanity check, + * just in case. + */ + if ( ld->x6_op == 1 || ld->x6_op == 3 ) { + printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n"); + die_if_kernel("unaligned reference on specualtive load with register update\n", + regs, 30); + } + + + /* + * at this point, we know that the base register to update is valid i.e., + * it's not r0 + */ + if ( type == UPD_IMMEDIATE ) { + unsigned long imm; + + /* + * Load +Imm: ldXZ r1=[r3],imm(9) + * + * + * form imm9: [13:19] contain the first 7 bits + */ + imm = ld->x << 7 | ld->imm; + + /* + * sign extend (1+8bits) if m set + */ + if (ld->m) imm |= SIGN_EXT9; + + /* + * ifa == r3 and we know that the NaT bit on r3 was clear so + * we can directly use ifa. + */ + ifa += imm; + + setreg(ld->r3, ifa, 0, regs); + + DPRINT(("ld.x=%d ld.m=%d imm=%ld r3=0x%lx\n", ld->x, ld->m, imm, ifa)); + + } else if ( ld->m ) { + unsigned long r2; + int nat_r2; + + /* + * Load +Reg Opcode: ldXZ r1=[r3],r2 + * + * Note: that we update r3 even in the case of ldfX.a + * (where the load does not happen) + * + * The way the load algorithm works, we know that r3 does not + * have its NaT bit set (would have gotten NaT consumption + * before getting the unaligned fault). So we can use ifa + * which equals r3 at this point. + * + * IMPORTANT: + * The above statement holds ONLY because we know that we + * never reach this code when trying to do a ldX.s. + * If we ever make it to here on an ldfX.s then + */ + getreg(ld->imm, &r2, &nat_r2, regs); + + ifa += r2; + + /* + * propagate Nat r2 -> r3 + */ + setreg(ld->r3, ifa, nat_r2, regs); + + DPRINT(("imm=%d r2=%ld r3=0x%lx nat_r2=%d\n",ld->imm, r2, ifa, nat_r2)); + } +} + + +static int +emulate_load_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +{ + unsigned long val; + unsigned int len = 1<< ld->x6_sz; + + /* + * the macro supposes sequential access (which is the case) + * if the first byte is an invalid address we return here. Otherwise + * there is a guard page at the top of the user's address page and + * the first access would generate a NaT consumption fault and return + * with a SIGSEGV, which is what we want. + * + * Note: the first argument is ignored + */ + if ( access_ok(VERIFY_READ, (void *)ifa, len) < 0 ) { + DPRINT(("verify area failed on %lx\n", ifa)); + return -1; + } + + /* + * r0, as target, doesn't need to be checked because Illegal Instruction + * faults have higher priority than unaligned faults. + * + * r0 cannot be found as the base as it would never generate an + * unaligned reference. + */ + + /* + * ldX.a we don't try to emulate anything but we must + * invalidate the ALAT entry. + * See comment below for explanation on how we handle ldX.a + */ + if ( ld->x6_op != 0x2 ) { + /* + * we rely on the macros in unaligned.h for now i.e., + * we let the compiler figure out how to read memory gracefully. + * + * We need this switch/case because the way the inline function + * works. The code is optimized by the compiler and looks like + * a single switch/case. + */ + switch(len) { + case 2: + val = ia64_get_unaligned((void *)ifa, 2); + break; + case 4: + val = ia64_get_unaligned((void *)ifa, 4); + break; + case 8: + val = ia64_get_unaligned((void *)ifa, 8); + break; + default: + DPRINT(("unknown size: x6=%d\n", ld->x6_sz)); + return -1; + } + + setreg(ld->r1, val, 0, regs); + } + + /* + * check for updates on any kind of loads + */ + if ( ld->op == 0x5 || ld->m ) + emulate_load_updates(ld->op == 0x5 ? UPD_IMMEDIATE: UPD_REG, + ld, regs, ifa); + + /* + * handling of various loads (based on EAS2.4): + * + * ldX.acq (ordered load): + * - acquire semantics would have been used, so force fence instead. + * + * + * ldX.c.clr (check load and clear): + * - if we get to this handler, it's because the entry was not in the ALAT. + * Therefore the operation reverts to a normal load + * + * ldX.c.nc (check load no clear): + * - same as previous one + * + * ldX.c.clr.acq (ordered check load and clear): + * - same as above for c.clr part. The load needs to have acquire semantics. So + * we use the fence semantics which is stronger and thus ensures correctness. + * + * ldX.a (advanced load): + * - suppose ldX.a r1=[r3]. If we get to the unaligned trap it's because the + * address doesn't match requested size alignement. This means that we would + * possibly need more than one load to get the result. + * + * The load part can be handled just like a normal load, however the difficult + * part is to get the right thing into the ALAT. The critical piece of information + * in the base address of the load & size. To do that, a ld.a must be executed, + * clearly any address can be pushed into the table by using ld1.a r1=[r3]. Now + * if we use the same target register, we will be okay for the check.a instruction. + * If we look at the store, basically a stX [r3]=r1 checks the ALAT for any entry + * which would overlap within [r3,r3+X] (the size of the load was store in the + * ALAT). If such an entry is found the entry is invalidated. But this is not good + * enough, take the following example: + * r3=3 + * ld4.a r1=[r3] + * + * Could be emulated by doing: + * ld1.a r1=[r3],1 + * store to temporary; + * ld1.a r1=[r3],1 + * store & shift to temporary; + * ld1.a r1=[r3],1 + * store & shift to temporary; + * ld1.a r1=[r3] + * store & shift to temporary; + * r1=temporary + * + * So int this case, you would get the right value is r1 but the wrong info in + * the ALAT. Notice that you could do it in reverse to finish with address 3 + * but you would still get the size wrong. To get the size right, one needs to + * execute exactly the same kind of load. You could do it from a aligned + * temporary location, but you would get the address wrong. + * + * So no matter what, it is not possible to emulate an advanced load + * correctly. But is that really critical ? + * + * + * Now one has to look at how ld.a is used, one must either do a ld.c.* or + * chck.a.* to reuse the value stored in the ALAT. Both can "fail" (meaning no + * entry found in ALAT), and that's perfectly ok because: + * + * - ld.c.*, if the entry is not present a normal load is executed + * - chk.a.*, if the entry is not present, execution jumps to recovery code + * + * In either case, the load can be potentially retried in another form. + * + * So it's okay NOT to do any actual load on an unaligned ld.a. However the ALAT + * must be invalidated for the register (so that's chck.a.*,ld.c.* don't pick up + * a stale entry later) The register base update MUST also be performed. + * + * Now what is the content of the register and its NaT bit in the case we don't + * do the load ? EAS2.4, says (in case an actual load is needed) + * + * - r1 = [r3], Nat = 0 if succeeds + * - r1 = 0 Nat = 0 if trying to access non-speculative memory + * + * For us, there is nothing to do, because both ld.c.* and chk.a.* are going to + * retry and thus eventually reload the register thereby changing Nat and + * register content. + */ + + /* + * when the load has the .acq completer then + * use ordering fence. + */ + if (ld->x6_op == 0x5 || ld->x6_op == 0xa) + mb(); + + /* + * invalidate ALAT entry in case of advanced load + */ + if (ld->x6_op == 0x2) + invala_gr(ld->r1); + + return 0; +} + +static int +emulate_store_int(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +{ + unsigned long r2; + unsigned int len = 1<< ld->x6_sz; + + /* + * the macro supposes sequential access (which is the case) + * if the first byte is an invalid address we return here. Otherwise + * there is a guard page at the top of the user's address page and + * the first access would generate a NaT consumption fault and return + * with a SIGSEGV, which is what we want. + * + * Note: the first argument is ignored + */ + if ( access_ok(VERIFY_WRITE, (void *)ifa, len) < 0 ) { + DPRINT(("verify area failed on %lx\n",ifa)); + return -1; + } + + /* + * if we get to this handler, Nat bits on both r3 and r2 have already + * been checked. so we don't need to do it + * + * extract the value to be stored + */ + getreg(ld->imm, &r2, 0, regs); + + /* + * we rely on the macros in unaligned.h for now i.e., + * we let the compiler figure out how to read memory gracefully. + * + * We need this switch/case because the way the inline function + * works. The code is optimized by the compiler and looks like + * a single switch/case. + */ + DPRINT(("st%d [%lx]=%lx\n", len, ifa, r2)); + + switch(len) { + case 2: + ia64_put_unaligned(r2, (void *)ifa, 2); + break; + case 4: + ia64_put_unaligned(r2, (void *)ifa, 4); + break; + case 8: + ia64_put_unaligned(r2, (void *)ifa, 8); + break; + default: + DPRINT(("unknown size: x6=%d\n", ld->x6_sz)); + return -1; + } + /* + * stX [r3]=r2,imm(9) + * + * NOTE: + * ld->r3 can never be r0, because r0 would not generate an + * unaligned access. + */ + if ( ld->op == 0x5 ) { + unsigned long imm; + + /* + * form imm9: [12:6] contain first 7bits + */ + imm = ld->x << 7 | ld->r1; + /* + * sign extend (8bits) if m set + */ + if ( ld->m ) imm |= SIGN_EXT9; + /* + * ifa == r3 (NaT is necessarily cleared) + */ + ifa += imm; + + DPRINT(("imm=%lx r3=%lx\n", imm, ifa)); + + setreg(ld->r3, ifa, 0, regs); + } + /* + * we don't have alat_invalidate_multiple() so we need + * to do the complete flush :-<< + */ + ia64_invala(); + + /* + * stX.rel: use fence instead of release + */ + if ( ld->x6_op == 0xd ) mb(); + + return 0; +} + +/* + * floating point operations sizes in bytes + */ +static const unsigned short float_fsz[4]={ + 16, /* extended precision (e) */ + 8, /* integer (8) */ + 4, /* single precision (s) */ + 8 /* double precision (d) */ +}; + +static inline void +mem2float_extended(struct ia64_fpreg *init, struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("ldfe f6=[%0];; stf.spill [%1]=f6" + :: "r"(init), "r"(final) : "f6","memory"); +} + +static inline void +mem2float_integer(struct ia64_fpreg *init, struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("ldf8 f6=[%0];; stf.spill [%1]=f6" + :: "r"(init), "r"(final) : "f6","memory"); +} + +static inline void +mem2float_single(struct ia64_fpreg *init, struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("ldfs f6=[%0];; stf.spill [%1]=f6" + :: "r"(init), "r"(final) : "f6","memory"); +} + +static inline void +mem2float_double(struct ia64_fpreg *init, struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("ldfd f6=[%0];; stf.spill [%1]=f6" + :: "r"(init), "r"(final) : "f6","memory"); +} + +static inline void +float2mem_extended(struct ia64_fpreg *init, struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("ldf.fill f6=[%0];; stfe [%1]=f6" + :: "r"(init), "r"(final) : "f6","memory"); +} + +static inline void +float2mem_integer(struct ia64_fpreg *init, struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("ldf.fill f6=[%0];; stf8 [%1]=f6" + :: "r"(init), "r"(final) : "f6","memory"); +} + +static inline void +float2mem_single(struct ia64_fpreg *init, struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("ldf.fill f6=[%0];; stfs [%1]=f6" + :: "r"(init), "r"(final) : "f6","memory"); +} + +static inline void +float2mem_double(struct ia64_fpreg *init, struct ia64_fpreg *final) +{ + __asm__ __volatile__ ("ldf.fill f6=[%0];; stfd [%1]=f6" + :: "r"(init), "r"(final) : "f6","memory"); +} + +static int +emulate_load_floatpair(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +{ + struct ia64_fpreg fpr_init[2]; + struct ia64_fpreg fpr_final[2]; + unsigned long len = float_fsz[ld->x6_sz]; + + if ( access_ok(VERIFY_READ, (void *)ifa, len<<1) < 0 ) { + DPRINT(("verify area failed on %lx\n", ifa)); + return -1; + } + /* + * fr0 & fr1 don't need to be checked because Illegal Instruction + * faults have higher priority than unaligned faults. + * + * r0 cannot be found as the base as it would never generate an + * unaligned reference. + */ + + /* + * make sure we get clean buffers + */ + memset(&fpr_init,0, sizeof(fpr_init)); + memset(&fpr_final,0, sizeof(fpr_final)); + + /* + * ldfpX.a: we don't try to emulate anything but we must + * invalidate the ALAT entry and execute updates, if any. + */ + if ( ld->x6_op != 0x2 ) { + /* + * does the unaligned access + */ + memcpy(&fpr_init[0], (void *)ifa, len); + memcpy(&fpr_init[1], (void *)(ifa+len), len); + + DPRINT(("ld.r1=%d ld.imm=%d x6_sz=%d\n", ld->r1, ld->imm, ld->x6_sz)); +#ifdef DEBUG_UNALIGNED_TRAP + { int i; char *c = (char *)&fpr_init; + printk("fpr_init= "); + for(i=0; i < len<<1; i++ ) { + printk("%02x ", c[i]&0xff); + } + printk("\n"); + } +#endif + /* + * XXX fixme + * Could optimize inlines by using ldfpX & 2 spills + */ + switch( ld->x6_sz ) { + case 0: + mem2float_extended(&fpr_init[0], &fpr_final[0]); + mem2float_extended(&fpr_init[1], &fpr_final[1]); + break; + case 1: + mem2float_integer(&fpr_init[0], &fpr_final[0]); + mem2float_integer(&fpr_init[1], &fpr_final[1]); + break; + case 2: + mem2float_single(&fpr_init[0], &fpr_final[0]); + mem2float_single(&fpr_init[1], &fpr_final[1]); + break; + case 3: + mem2float_double(&fpr_init[0], &fpr_final[0]); + mem2float_double(&fpr_init[1], &fpr_final[1]); + break; + } +#ifdef DEBUG_UNALIGNED_TRAP + { int i; char *c = (char *)&fpr_final; + printk("fpr_final= "); + for(i=0; i < len<<1; i++ ) { + printk("%02x ", c[i]&0xff); + } + printk("\n"); + } +#endif + /* + * XXX fixme + * + * A possible optimization would be to drop fpr_final + * and directly use the storage from the saved context i.e., + * the actual final destination (pt_regs, switch_stack or tss). + */ + setfpreg(ld->r1, &fpr_final[0], regs); + setfpreg(ld->imm, &fpr_final[1], regs); + } + + /* + * Check for updates: only immediate updates are available for this + * instruction. + */ + if ( ld->m ) { + + /* + * the immediate is implicit given the ldsz of the operation: + * single: 8 (2x4) and for all others it's 16 (2x8) + */ + ifa += len<<1; + + /* + * IMPORTANT: + * the fact that we force the NaT of r3 to zero is ONLY valid + * as long as we don't come here with a ldfpX.s. + * For this reason we keep this sanity check + */ + if ( ld->x6_op == 1 || ld->x6_op == 3 ) { + printk(KERN_ERR "%s: register update on speculative load pair, error\n", __FUNCTION__); + } + + + setreg(ld->r3, ifa, 0, regs); + } + + /* + * Invalidate ALAT entries, if any, for both registers. + */ + if ( ld->x6_op == 0x2 ) { + invala_fr(ld->r1); + invala_fr(ld->imm); + } + return 0; +} + + +static int +emulate_load_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +{ + struct ia64_fpreg fpr_init; + struct ia64_fpreg fpr_final; + unsigned long len = float_fsz[ld->x6_sz]; + + /* + * check for load pair because our masking scheme is not fine grain enough + if ( ld->x == 1 ) return emulate_load_floatpair(ifa,ld,regs); + */ + + if ( access_ok(VERIFY_READ, (void *)ifa, len) < 0 ) { + DPRINT(("verify area failed on %lx\n", ifa)); + return -1; + } + /* + * fr0 & fr1 don't need to be checked because Illegal Instruction + * faults have higher priority than unaligned faults. + * + * r0 cannot be found as the base as it would never generate an + * unaligned reference. + */ + + + /* + * make sure we get clean buffers + */ + memset(&fpr_init,0, sizeof(fpr_init)); + memset(&fpr_final,0, sizeof(fpr_final)); + + /* + * ldfX.a we don't try to emulate anything but we must + * invalidate the ALAT entry. + * See comments in ldX for descriptions on how the various loads are handled. + */ + if ( ld->x6_op != 0x2 ) { + + /* + * does the unaligned access + */ + memcpy(&fpr_init, (void *)ifa, len); + + DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz)); +#ifdef DEBUG_UNALIGNED_TRAP + { int i; char *c = (char *)&fpr_init; + printk("fpr_init= "); + for(i=0; i < len; i++ ) { + printk("%02x ", c[i]&0xff); + } + printk("\n"); + } +#endif + /* + * we only do something for x6_op={0,8,9} + */ + switch( ld->x6_sz ) { + case 0: + mem2float_extended(&fpr_init, &fpr_final); + break; + case 1: + mem2float_integer(&fpr_init, &fpr_final); + break; + case 2: + mem2float_single(&fpr_init, &fpr_final); + break; + case 3: + mem2float_double(&fpr_init, &fpr_final); + break; + } +#ifdef DEBUG_UNALIGNED_TRAP + { int i; char *c = (char *)&fpr_final; + printk("fpr_final= "); + for(i=0; i < len; i++ ) { + printk("%02x ", c[i]&0xff); + } + printk("\n"); + } +#endif + /* + * XXX fixme + * + * A possible optimization would be to drop fpr_final + * and directly use the storage from the saved context i.e., + * the actual final destination (pt_regs, switch_stack or tss). + */ + setfpreg(ld->r1, &fpr_final, regs); + } + + /* + * check for updates on any loads + */ + if ( ld->op == 0x7 || ld->m ) + emulate_load_updates(ld->op == 0x7 ? UPD_IMMEDIATE: UPD_REG, + ld, regs, ifa); + + + /* + * invalidate ALAT entry in case of advanced floating point loads + */ + if (ld->x6_op == 0x2) + invala_fr(ld->r1); + + return 0; +} + + +static int +emulate_store_float(unsigned long ifa, load_store_t *ld, struct pt_regs *regs) +{ + struct ia64_fpreg fpr_init; + struct ia64_fpreg fpr_final; + unsigned long len = float_fsz[ld->x6_sz]; + + /* + * the macro supposes sequential access (which is the case) + * if the first byte is an invalid address we return here. Otherwise + * there is a guard page at the top of the user's address page and + * the first access would generate a NaT consumption fault and return + * with a SIGSEGV, which is what we want. + * + * Note: the first argument is ignored + */ + if ( access_ok(VERIFY_WRITE, (void *)ifa, len) < 0 ) { + DPRINT(("verify area failed on %lx\n",ifa)); + return -1; + } + + /* + * make sure we get clean buffers + */ + memset(&fpr_init,0, sizeof(fpr_init)); + memset(&fpr_final,0, sizeof(fpr_final)); + + + /* + * if we get to this handler, Nat bits on both r3 and r2 have already + * been checked. so we don't need to do it + * + * extract the value to be stored + */ + getfpreg(ld->imm, &fpr_init, regs); + /* + * during this step, we extract the spilled registers from the saved + * context i.e., we refill. Then we store (no spill) to temporary + * aligned location + */ + switch( ld->x6_sz ) { + case 0: + float2mem_extended(&fpr_init, &fpr_final); + break; + case 1: + float2mem_integer(&fpr_init, &fpr_final); + break; + case 2: + float2mem_single(&fpr_init, &fpr_final); + break; + case 3: + float2mem_double(&fpr_init, &fpr_final); + break; + } + DPRINT(("ld.r1=%d x6_sz=%d\n", ld->r1, ld->x6_sz)); +#ifdef DEBUG_UNALIGNED_TRAP + { int i; char *c = (char *)&fpr_init; + printk("fpr_init= "); + for(i=0; i < len; i++ ) { + printk("%02x ", c[i]&0xff); + } + printk("\n"); + } + { int i; char *c = (char *)&fpr_final; + printk("fpr_final= "); + for(i=0; i < len; i++ ) { + printk("%02x ", c[i]&0xff); + } + printk("\n"); + } +#endif + + /* + * does the unaligned store + */ + memcpy((void *)ifa, &fpr_final, len); + + /* + * stfX [r3]=r2,imm(9) + * + * NOTE: + * ld->r3 can never be r0, because r0 would not generate an + * unaligned access. + */ + if ( ld->op == 0x7 ) { + unsigned long imm; + + /* + * form imm9: [12:6] contain first 7bits + */ + imm = ld->x << 7 | ld->r1; + /* + * sign extend (8bits) if m set + */ + if ( ld->m ) imm |= SIGN_EXT9; + /* + * ifa == r3 (NaT is necessarily cleared) + */ + ifa += imm; + + DPRINT(("imm=%lx r3=%lx\n", imm, ifa)); + + setreg(ld->r3, ifa, 0, regs); + } + /* + * we don't have alat_invalidate_multiple() so we need + * to do the complete flush :-<< + */ + ia64_invala(); + + return 0; +} + +void +ia64_handle_unaligned(unsigned long ifa, struct pt_regs *regs) +{ + static unsigned long unalign_count; + static long last_time; + + struct ia64_psr *ipsr = ia64_psr(regs); + unsigned long *bundle_addr; + unsigned long opcode; + unsigned long op; + load_store_t *insn; + int ret = -1; + + /* + * We flag unaligned references while in kernel as + * errors: the kernel must be fixed. The switch code + * is in ivt.S at entry 30. + * + * So here we keep a simple sanity check. + */ + if ( !user_mode(regs) ) { + die_if_kernel("Unaligned reference while in kernel\n", regs, 30); + /* NOT_REACHED */ + } + + /* + * Make sure we log the unaligned access, so that user/sysadmin can notice it + * and eventually fix the program. + * + * We don't want to do that for every access so we pace it with jiffies. + */ + if ( unalign_count > 5 && jiffies - last_time > 5*HZ ) unalign_count = 0; + if ( ++unalign_count < 5 ) { + last_time = jiffies; + printk("%s(%d): unaligned trap accessing %016lx (ip=%016lx)\n", + current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); + + } + + DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr)); + DPRINT(("ISR.ei=%d ISR.sp=%d\n", ipsr->ri, ipsr->it)); + + bundle_addr = (unsigned long *)(regs->cr_iip); + + /* + * extract the instruction from the bundle given the slot number + */ + switch ( ipsr->ri ) { + case 0: op = *bundle_addr >> 5; + break; + + case 1: op = *bundle_addr >> 46 | (*(bundle_addr+1) & 0x7fffff)<<18; + break; + + case 2: op = *(bundle_addr+1) >> 23; + break; + } + + insn = (load_store_t *)&op; + opcode = op & IA64_OPCODE_MASK; + + DPRINT(("opcode=%lx ld.qp=%d ld.r1=%d ld.imm=%d ld.r3=%d ld.x=%d ld.hint=%d " + "ld.x6=0x%x ld.m=%d ld.op=%d\n", + opcode, + insn->qp, + insn->r1, + insn->imm, + insn->r3, + insn->x, + insn->hint, + insn->x6_sz, + insn->m, + insn->op)); + + /* + * IMPORTANT: + * Notice that the swictch statement DOES not cover all possible instructions + * that DO generate unaligned references. This is made on purpose because for some + * instructions it DOES NOT make sense to try and emulate the access. Sometimes it + * is WRONG to try and emulate. Here is a list of instruction we don't emulate i.e., + * the program will get a signal and die: + * + * load/store: + * - ldX.spill + * - stX.spill + * Reason: RNATs are based on addresses + * + * synchronization: + * - cmpxchg + * - fetchadd + * - xchg + * Reason: ATOMIC operations cannot be emulated properly using multiple + * instructions. + * + * speculative loads: + * - ldX.sZ + * Reason: side effects, code must be ready to deal with failure so simpler + * to let the load fail. + * --------------------------------------------------------------------------------- + * XXX fixme + * + * I would like to get rid of this switch case and do something + * more elegant. + */ + switch(opcode) { + case LDS_OP: + case LDSA_OP: + case LDS_IMM_OP: + case LDSA_IMM_OP: + case LDFS_OP: + case LDFSA_OP: + case LDFS_IMM_OP: + /* + * The instruction will be retried with defered exceptions + * turned on, and we should get Nat bit installed + * + * IMPORTANT: + * When PSR_ED is set, the register & immediate update + * forms are actually executed even though the operation + * failed. So we don't need to take care of this. + */ + DPRINT(("forcing PSR_ED\n")); + regs->cr_ipsr |= IA64_PSR_ED; + return; + + case LD_OP: + case LDA_OP: + case LDBIAS_OP: + case LDACQ_OP: + case LDCCLR_OP: + case LDCNC_OP: + case LDCCLRACQ_OP: + case LD_IMM_OP: + case LDA_IMM_OP: + case LDBIAS_IMM_OP: + case LDACQ_IMM_OP: + case LDCCLR_IMM_OP: + case LDCNC_IMM_OP: + case LDCCLRACQ_IMM_OP: + ret = emulate_load_int(ifa, insn, regs); + break; + case ST_OP: + case STREL_OP: + case ST_IMM_OP: + case STREL_IMM_OP: + ret = emulate_store_int(ifa, insn, regs); + break; + case LDF_OP: + case LDFA_OP: + case LDFCCLR_OP: + case LDFCNC_OP: + case LDF_IMM_OP: + case LDFA_IMM_OP: + case LDFCCLR_IMM_OP: + case LDFCNC_IMM_OP: + ret = insn->x ? + emulate_load_floatpair(ifa, insn, regs): + emulate_load_float(ifa, insn, regs); + break; + case STF_OP: + case STF_IMM_OP: + ret = emulate_store_float(ifa, insn, regs); + } + + DPRINT(("ret=%d\n", ret)); + if ( ret ) { + lock_kernel(); + force_sig(SIGSEGV, current); + unlock_kernel(); + } else { + /* + * given today's architecture this case is not likely to happen + * because a memory access instruction (M) can never be in the + * last slot of a bundle. But let's keep it for now. + */ + if ( ipsr->ri == 2 ) regs->cr_iip += 16; + ipsr->ri = ++ipsr->ri & 3; + } + + DPRINT(("ipsr->ri=%d iip=%lx\n", ipsr->ri, regs->cr_iip)); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c --- v2.3.42/linux/arch/ia64/kernel/unwind.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/unwind.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,118 @@ +/* + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + */ +#include +#include + +#include + +void +ia64_unwind_init_from_blocked_task (struct ia64_frame_info *info, struct task_struct *t) +{ + struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16); + unsigned long sol, limit, top; + + memset(info, 0, sizeof(*info)); + + sol = (sw->ar_pfs >> 7) & 0x7f; /* size of locals */ + + limit = (unsigned long) t + IA64_RBS_OFFSET; + top = sw->ar_bspstore; + if (top - (unsigned long) t >= IA64_STK_OFFSET) + top = limit; + + info->regstk.limit = (unsigned long *) limit; + info->regstk.top = (unsigned long *) top; + info->bsp = ia64_rse_skip_regs(info->regstk.top, -sol); + info->top_rnat = sw->ar_rnat; + info->cfm = sw->ar_pfs; + info->ip = sw->b0; +} + +void +ia64_unwind_init_from_current (struct ia64_frame_info *info, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *) regs - 1; + unsigned long sol, sof, *bsp, limit, top; + + limit = (unsigned long) current + IA64_RBS_OFFSET; + top = sw->ar_bspstore; + if (top - (unsigned long) current >= IA64_STK_OFFSET) + top = limit; + + memset(info, 0, sizeof(*info)); + + sol = (sw->ar_pfs >> 7) & 0x7f; /* size of frame */ + info->regstk.limit = (unsigned long *) limit; + info->regstk.top = (unsigned long *) top; + info->top_rnat = sw->ar_rnat; + + /* this gives us the bsp top level frame (kdb interrupt frame): */ + bsp = ia64_rse_skip_regs((unsigned long *) top, -sol); + + /* now skip past the interrupt frame: */ + sof = regs->cr_ifs & 0x7f; /* size of frame */ + info->cfm = regs->cr_ifs; + info->bsp = ia64_rse_skip_regs(bsp, -sof); + info->ip = regs->cr_iip; +} + +static unsigned long +read_reg (struct ia64_frame_info *info, int regnum, int *is_nat) +{ + unsigned long *addr, *rnat_addr, rnat; + + addr = ia64_rse_skip_regs(info->bsp, regnum); + if (addr < info->regstk.limit || addr >= info->regstk.top || ((long) addr & 0x7) != 0) { + *is_nat = 1; + return 0xdeadbeefdeadbeef; + } + rnat_addr = ia64_rse_rnat_addr(addr); + + if (rnat_addr >= info->regstk.top) + rnat = info->top_rnat; + else + rnat = *rnat_addr; + *is_nat = (rnat & (1UL << ia64_rse_slot_num(addr))) != 0; + return *addr; +} + +/* + * On entry, info->regstk.top should point to the register backing + * store for r32. + */ +int +ia64_unwind_to_previous_frame (struct ia64_frame_info *info) +{ + unsigned long sol, cfm = info->cfm; + int is_nat; + + sol = (cfm >> 7) & 0x7f; /* size of locals */ + + /* + * In general, we would have to make use of unwind info to + * unwind an IA-64 stack, but for now gcc uses a special + * convention that makes this possible without full-fledged + * unwindo info. Specifically, we expect "rp" in the second + * last, and "ar.pfs" in the last local register, so the + * number of locals in a frame must be at least two. If it's + * less than that, we reached the end of the C call stack. + */ + if (sol < 2) + return -1; + + info->ip = read_reg(info, sol - 2, &is_nat); + if (is_nat) + return -1; + + cfm = read_reg(info, sol - 1, &is_nat); + if (is_nat) + return -1; + + sol = (cfm >> 7) & 0x7f; + + info->cfm = cfm; + info->bsp = ia64_rse_skip_regs(info->bsp, -sol); + return 0; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile --- v2.3.42/linux/arch/ia64/lib/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,42 @@ +# +# Makefile for ia64-specific library routines.. +# + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $@ + +OBJS = __divdi3.o __divsi3.o __udivdi3.o __udivsi3.o \ + __moddi3.o __modsi3.o __umoddi3.o __umodsi3.o \ + checksum.o clear_page.o csum_partial_copy.o copy_page.o \ + copy_user.o clear_user.o memset.o strncpy_from_user.o \ + strlen.o strlen_user.o strnlen_user.o \ + flush.o do_csum.o + +lib.a: $(OBJS) + $(AR) rcs lib.a $(OBJS) + +__divdi3.o: idiv.S + $(CC) $(AFLAGS) -c -o $@ $< + +__divsi3.o: idiv.S + $(CC) $(AFLAGS) -c -DSINGLE -c -o $@ $< + +__udivdi3.o: idiv.S + $(CC) $(AFLAGS) -c -DUNSIGNED -c -o $@ $< + +__udivsi3.o: idiv.S + $(CC) $(AFLAGS) -c -DUNSIGNED -DSINGLE -c -o $@ $< + +__moddi3.o: idiv.S + $(CC) $(AFLAGS) -c -DMODULO -c -o $@ $< + +__modsi3.o: idiv.S + $(CC) $(AFLAGS) -c -DMODULO -DSINGLE -c -o $@ $< + +__umoddi3.o: idiv.S + $(CC) $(AFLAGS) -c -DMODULO -DUNSIGNED -c -o $@ $< + +__umodsi3.o: idiv.S + $(CC) $(AFLAGS) -c -DMODULO -DUNSIGNED -DSINGLE -c -o $@ $< + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/checksum.c linux/arch/ia64/lib/checksum.c --- v2.3.42/linux/arch/ia64/lib/checksum.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/checksum.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,110 @@ +/* + * Network checksum routines + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + * + * Most of the code coming from arch/alpha/lib/checksum.c + * + * This file contains network checksum routines that are better done + * in an architecture-specific manner due to speed.. + */ + +#include + +#include + +static inline unsigned short +from64to16(unsigned long x) +{ + /* add up 32-bit words for 33 bits */ + x = (x & 0xffffffff) + (x >> 32); + /* add up 16-bit and 17-bit words for 17+c bits */ + x = (x & 0xffff) + (x >> 16); + /* add up 16-bit and 2-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented. + */ +unsigned short int csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + return ~from64to16(saddr + daddr + sum + + ((unsigned long) ntohs(len) << 16) + + ((unsigned long) proto << 8)); +} + +unsigned int csum_tcpudp_nofold(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + unsigned long result; + + result = (saddr + daddr + sum + + ((unsigned long) ntohs(len) << 16) + + ((unsigned long) proto << 8)); + + /* Fold down to 32-bits so we don't loose in the typedef-less + network stack. */ + /* 64 to 33 */ + result = (result & 0xffffffff) + (result >> 32); + /* 33 to 32 */ + result = (result & 0xffffffff) + (result >> 32); + return result; +} + +extern unsigned long do_csum(const unsigned char *, unsigned int, unsigned int); +extern unsigned long do_csum_c(const unsigned char *, unsigned int, unsigned int); + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) +{ + return ~do_csum(iph,ihl*4,0); +} + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * 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 long result = do_csum(buff, len, 0); + + /* add in old sum, and carry.. */ + result += sum; + /* 32+c bits -> 32 bits */ + result = (result & 0xffffffff) + (result >> 32); + return result; +} + + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +unsigned short ip_compute_csum(unsigned char * buff, int len) +{ + return ~do_csum(buff,len, 0); +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/clear_page.S linux/arch/ia64/lib/clear_page.S --- v2.3.42/linux/arch/ia64/lib/clear_page.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/clear_page.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,42 @@ +/* + * + * Optimized version of the standard clearpage() function + * + * Based on comments from ddd. Try not to overflow the write buffer. + * + * Inputs: + * in0: address of page + * + * Output: + * none + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + * Copyright (C) 1999 David Mosberger-Tang + */ +#include + + .text + .psr abi64 + .psr lsb + .lsb + + .align 32 + .global clear_page + .proc clear_page +clear_page: + alloc r11=ar.pfs,1,0,0,0 + mov r16=ar.lc // slow + mov r17=PAGE_SIZE/32-1 // -1 = repeat/until + ;; + adds r18=16,in0 + mov ar.lc=r17 + ;; +1: stf.spill.nta [in0]=f0,32 + stf.spill.nta [r18]=f0,32 + br.cloop.dptk.few 1b + ;; + mov ar.lc=r16 // restore lc + br.ret.sptk.few rp + + .endp clear_page diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S --- v2.3.42/linux/arch/ia64/lib/clear_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/clear_user.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,224 @@ +/* + * This routine clears to zero a linear memory buffer in user space. + * + * Inputs: + * in0: address of buffer + * in1: length of buffer in bytes + * Outputs: + * r8: number of bytes that didn't get cleared due to a fault + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + */ + +// +// arguments +// +#define buf r32 +#define len r33 + +// +// local registers +// +#define cnt r16 +#define buf2 r17 +#define saved_lc r18 +#define saved_pr r19 +#define saved_pfs r20 +#define tmp r21 +#define len2 r22 +#define len3 r23 + +// +// Theory of operations: +// - we check whether or not the buffer is small, i.e., less than 17 +// in which case we do the byte by byte loop. +// +// - Otherwise we go progressively from 1 byte store to 8byte store in +// the head part, the body is a 16byte store loop and we finish we the +// tail for the last 15 bytes. +// The good point about this breakdown is that the long buffer handling +// contains only 2 branches. +// +// The reason for not using shifting & masking for both the head and the +// tail is to stay semantically correct. This routine is not supposed +// to write bytes outside of the buffer. While most of the time this would +// be ok, we can't tolerate a mistake. A classical example is the case +// of multithreaded code were to the extra bytes touched is actually owned +// by another thread which runs concurrently to ours. Another, less likely, +// example is with device drivers where reading an I/O mapped location may +// have side effects (same thing for writing). +// + +// The label comes first because our store instruction contains a comma +// and confuse the preprocessor otherwise +// +#define EX(y,x...) \ + .section __ex_table,"a"; \ + data4 @gprel(99f); \ + data4 y-99f; \ + .previous; \ +99: x + + .text + .psr abi64 + .psr lsb + .lsb + + .align 32 + .global __do_clear_user + .proc __do_clear_user + +__do_clear_user: + alloc saved_pfs=ar.pfs,2,0,0,0 + cmp.eq p6,p0=r0,len // check for zero length + mov saved_lc=ar.lc // preserve ar.lc (slow) + ;; // avoid WAW on CFM + adds tmp=-1,len // br.ctop is repeat/until + mov ret0=len // return value is length at this point +(p6) br.ret.spnt.few rp + ;; + cmp.lt p6,p0=16,len // if len > 16 then long memset + mov ar.lc=tmp // initialize lc for small count +(p6) br.cond.dptk.few long_do_clear + ;; // WAR on ar.lc + // + // worst case 16 cyles, avg 8 cycles + // + // We could have played with the predicates to use the extra + // M slot for 2 stores/iteration but the cost the initialization + // the various counters compared to how long the loop is supposed + // to last on average does not make this solution viable. + // +1: + EX( .Lexit1, st1 [buf]=r0,1 ) + adds len=-1,len // countdown length using len + br.cloop.dptk.few 1b + ;; // avoid RAW on ar.lc + // + // .Lexit4: comes from byte by byte loop + // len contains bytes left +.Lexit1: + mov ret0=len // faster than using ar.lc + mov ar.lc=saved_lc + br.ret.sptk.few rp // end of short clear_user + + + // + // At this point we know we have more than 16 bytes to copy + // so we focus on alignment (no branches required) + // + // The use of len/len2 for countdown of the number of bytes left + // instead of ret0 is due to the fact that the exception code + // changes the values of r8. + // +long_do_clear: + tbit.nz p6,p0=buf,0 // odd alignment (for long_do_clear) + ;; + EX( .Lexit3, (p6) st1 [buf]=r0,1 ) // 1-byte aligned +(p6) adds len=-1,len;; // sync because buf is modified + tbit.nz p6,p0=buf,1 + ;; + EX( .Lexit3, (p6) st2 [buf]=r0,2 ) // 2-byte aligned +(p6) adds len=-2,len;; + tbit.nz p6,p0=buf,2 + ;; + EX( .Lexit3, (p6) st4 [buf]=r0,4 ) // 4-byte aligned +(p6) adds len=-4,len;; + tbit.nz p6,p0=buf,3 + ;; + EX( .Lexit3, (p6) st8 [buf]=r0,8 ) // 8-byte aligned +(p6) adds len=-8,len;; + shr.u cnt=len,4 // number of 128-bit (2x64bit) words + ;; + cmp.eq p6,p0=r0,cnt + adds tmp=-1,cnt +(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left + ;; + adds buf2=8,buf // setup second base pointer + mov ar.lc=tmp + ;; + + // + // 16bytes/iteration core loop + // + // The second store can never generate a fault because + // we come into the loop only when we are 16-byte aligned. + // This means that if we cross a page then it will always be + // in the first store and never in the second. + // + // + // We need to keep track of the remaining length. A possible (optimistic) + // way would be to ue ar.lc and derive how many byte were left by + // doing : left= 16*ar.lc + 16. this would avoid the addition at + // every iteration. + // However we need to keep the synchronization point. A template + // M;;MB does not exist and thus we can keep the addition at no + // extra cycle cost (use a nop slot anyway). It also simplifies the + // (unlikely) error recovery code + // + +2: + + EX(.Lexit3, st8 [buf]=r0,16 ) + ;; // needed to get len correct when error + st8 [buf2]=r0,16 + adds len=-16,len + br.cloop.dptk.few 2b + ;; + mov ar.lc=saved_lc + // + // tail correction based on len only + // + // We alternate the use of len3,len2 to allow parallelism and correct + // error handling. We also reuse p6/p7 to return correct value. + // The addition of len2/len3 does not cost anything more compared to + // the regular memset as we had empty slots. + // +.dotail: + mov len2=len // for parallelization of error handling + mov len3=len + tbit.nz p6,p0=len,3 + ;; + EX( .Lexit2, (p6) st8 [buf]=r0,8 ) // at least 8 bytes +(p6) adds len3=-8,len2 + tbit.nz p7,p6=len,2 + ;; + EX( .Lexit2, (p7) st4 [buf]=r0,4 ) // at least 4 bytes +(p7) adds len2=-4,len3 + tbit.nz p6,p7=len,1 + ;; + EX( .Lexit2, (p6) st2 [buf]=r0,2 ) // at least 2 bytes +(p6) adds len3=-2,len2 + tbit.nz p7,p6=len,0 + ;; + EX( .Lexit2, (p7) st1 [buf]=r0 ) // only 1 byte left + mov ret0=r0 // success + br.ret.dptk.few rp // end of most likely path + + // + // Outlined error handling code + // + + // + // .Lexit3: comes from core loop, need restore pr/lc + // len contains bytes left + // + // + // .Lexit2: + // if p6 -> coming from st8 or st2 : len2 contains what's left + // if p7 -> coming from st4 or st1 : len3 contains what's left + // We must restore lc/pr even though might not have been used. +.Lexit2: +(p6) mov len=len2 +(p7) mov len=len3 + ;; + // + // .Lexit4: comes from head, need not restore pr/lc + // len contains bytes left + // +.Lexit3: + mov ret0=len + mov ar.lc=saved_lc + br.ret.dptk.few rp + .endp diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/copy_page.S linux/arch/ia64/lib/copy_page.S --- v2.3.42/linux/arch/ia64/lib/copy_page.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/copy_page.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,87 @@ +/* + * + * Optimized version of the standard copy_page() function + * + * Based on comments from ddd. Try not to overflow write buffer. + * + * Inputs: + * in0: address of target page + * in1: address of source page + * Output: + * no return value + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + */ +#include + +#define lcount r16 +#define saved_pr r17 +#define saved_lc r18 +#define saved_pfs r19 +#define src1 r20 +#define src2 r21 +#define tgt1 r22 +#define tgt2 r23 + + .text + .psr abi64 + .psr lsb + .lsb + + .align 32 + .global copy_page + .proc copy_page + +copy_page: + alloc saved_pfs=ar.pfs,10,0,0,8 // we need 6 roatating (8 minimum) + // + 2 input + + .rotr t1[4], t2[4] // our 2 pipelines with depth of 4 each + + mov saved_lc=ar.lc // save ar.lc ahead of time + mov saved_pr=pr // rotating predicates are preserved + // resgisters we must save. + mov src1=in1 // initialize 1st stream source + adds src2=8,in1 // initialize 2nd stream source + mov lcount=PAGE_SIZE/16-1 // as many 16bytes as there are on a page + // -1 is because br.ctop is repeat/until + + adds tgt2=8,in0 // initialize 2nd stream target + mov tgt1=in0 // initialize 1st stream target + ;; + mov pr.rot=1<<16 // pr16=1 & pr[17-63]=0 , 63 not modified + + mov ar.lc=lcount // set loop counter + mov ar.ec=4 // ar.ec must match pipeline depth + ;; + + // We need to preload the n-1 stages of the pipeline (n=depth). + // We do this during the "prolog" of the loop: we execute + // n-1 times the "load" bundle. Then both loads & stores are + // enabled until we reach the end of the last word of the page + // on the load side. Then, we enter the epilogue (controlled by ec) + // where we just do the stores and no loads n-1 times : drain the pipe. + // + // The initialization of the prolog is done via the predicate registers: + // the choice of pr19 DEPENDS on the depth of the pipeline (n). + // When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62 + // are then shifted right at every iteration, + // Thus by initializing pr16=1 and pr17-19=0 (19=16+4-1) before the loop + // we get pr19=1 after 4 iterations (n in our case). + // +1: // engage loop now, let the magic happen... +(p16) ld8 t1[0]=[src1],16 // new data on top of pipeline in 1st stream +(p16) ld8 t2[0]=[src2],16 // new data on top of pipeline in 2nd stream + nop.i 0x0 +(p19) st8 [tgt1]=t1[3],16 // store top of 1st pipeline +(p19) st8 [tgt2]=t2[3],16 // store top of 2nd pipeline + br.ctop.dptk.few 1b // once lc==0, ec-- & p16=0 + // stores but no loads anymore + ;; + mov pr=saved_pr,0xffffffffffff0000 // restore predicates + mov ar.pfs=saved_pfs // restore ar.ec + mov ar.lc=saved_lc // restore saved lc + br.ret.sptk.few rp // bye... + + .endp copy_page diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S --- v2.3.42/linux/arch/ia64/lib/copy_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/copy_user.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,71 @@ +/* + * This routine copies a linear memory buffer across the user/kernel boundary. When + * reading a byte from the source causes a fault, the remainder of the destination + * buffer is zeroed out. Note that this can happen only when copying from user + * to kernel memory and we do this to absolutely guarantee that the + * kernel doesn't operate on random data. + * + * This file is derived from arch/alpha/lib/copy_user.S. + * + * Inputs: + * in0: address of destination buffer + * in1: address of source buffer + * in2: length of buffer in bytes + * Outputs: + * r8: number of bytes that didn't get copied due to a fault + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + */ + +#define EXI(x...) \ +99: x; \ + .section __ex_table,"a"; \ + data4 @gprel(99b); \ + data4 .Lexit_in-99b; \ + .previous + +#define EXO(x...) \ +99: x; \ + .section __ex_table,"a"; \ + data4 @gprel(99b); \ + data4 .Lexit_out-99b; \ + .previous + + .text + .psr abi64 + .psr lsb + .lsb + + .align 32 + .global __copy_user + .proc __copy_user +__copy_user: + alloc r10=ar.pfs,3,0,0,0 + mov r9=ar.lc // save ar.lc + mov ar.lc=in2 // set ar.lc to length of buffer + br.sptk.few .Lentr + + // XXX braindead copy loop---this needs to be optimized +.Loop1: + EXI(ld1 r8=[in1],1) + ;; + EXO(st1 [in0]=r8,1) +.Lentr: br.cloop.dptk.few .Loop1 // repeat unless ar.lc--==0 + ;; // avoid RAW on ar.lc +.Lexit_out: + mov r8=ar.lc // return how many bytes we _didn't_ copy + mov ar.lc=r9 + br.ret.sptk.few rp + +.Lexit_in: + // clear the remainder of the buffer: + mov r8=ar.lc // return how many bytes we _didn't_ copy +.Loop2: + st1 [in0]=r0,1 // this cannot fault because we get here only on user->kernel copies + br.cloop.dptk.few .Loop2 + ;; // avoid RAW on ar.lc + mov ar.lc=r9 + br.ret.sptk.few rp + + .endp __copy_user diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/csum_partial_copy.c linux/arch/ia64/lib/csum_partial_copy.c --- v2.3.42/linux/arch/ia64/lib/csum_partial_copy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/csum_partial_copy.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,165 @@ +/* + * Network Checksum & Copy routine + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + * + * Most of the code has been imported from Linux/Alpha + */ + +#include +#include + +#include + +/* + * XXX Fixme: those 2 inlines are meant for debugging and will go away + */ +static inline unsigned +short from64to16(unsigned long x) +{ + /* add up 32-bit words for 33 bits */ + x = (x & 0xffffffff) + (x >> 32); + /* add up 16-bit and 17-bit words for 17+c bits */ + x = (x & 0xffff) + (x >> 16); + /* add up 16-bit and 2-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +static inline +unsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum) +{ + int odd, count; + unsigned long result = (unsigned long)psum; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff << 8; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + if (4 & (unsigned long) buff) { + result += *(unsigned int *) buff; + count--; + len -= 4; + buff += 4; + } + count >>= 1; /* nr of 64-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 8; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffffffff) + (result >> 32); + } + if (len & 4) { + result += *(unsigned int *) buff; + buff += 4; + } + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += *buff; + + result = from64to16(result); + + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); + +out: + return result; +} + +/* + * XXX Fixme + * + * This is very ugly but temporary. THIS NEEDS SERIOUS ENHANCEMENTS. + * But it's very tricky to get right even in C. + */ +extern unsigned long do_csum(const unsigned char *, int); + +static unsigned int +do_csum_partial_copy_from_user (const char *src, char *dst, int len, + unsigned int psum, int *errp) +{ + const unsigned char *psrc = src; + unsigned long result; + int cplen = len; + int r = 0; + + /* XXX Fixme + * for now we separate the copy from checksum for obvious + * alignment difficulties. Look at the Alpha code and you'll be + * scared. + */ + + while ( cplen-- ) r |=__get_user(*dst++,psrc++); + + if ( r && errp ) *errp = r; + + result = do_csum(src, len); + + /* add in old sum, and carry.. */ + result += psum; + /* 32+c bits -> 32 bits */ + result = (result & 0xffffffff) + (result >> 32); + return result; +} + +unsigned int +csum_partial_copy_from_user(const char *src, char *dst, int len, + unsigned int sum, int *errp) +{ + if (!access_ok(src, len, VERIFY_READ)) { + *errp = -EFAULT; + memset(dst, 0, len); + return sum; + } + + return do_csum_partial_copy_from_user(src, dst, len, sum, errp); +} + +unsigned int +csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum) +{ + return do_csum_partial_copy_from_user(src, dst, len, sum, NULL); +} + +unsigned int +csum_partial_copy (const char *src, char *dst, int len, unsigned int sum) +{ + unsigned int ret; + int error = 0; + + ret = do_csum_partial_copy_from_user(src, dst, len, sum, &error); + if (error) + printk("csum_partial_copy_old(): tell mingo to convert me!\n"); + + return ret; +} + diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/do_csum.S linux/arch/ia64/lib/do_csum.S --- v2.3.42/linux/arch/ia64/lib/do_csum.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/do_csum.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,230 @@ +/* + * + * Optmized version of the standard do_csum() function + * + * Return: a 64bit quantity containing the 16bit Internet checksum + * + * Inputs: + * in0: address of buffer to checksum (char *) + * in1: length of the buffer (int) + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + * + */ + +// +// Theory of operations: +// The goal is to go as quickly as possible to the point where +// we can checksum 8 bytes/loop. Before reaching that point we must +// take care of incorrect alignment of first byte. +// +// The code hereafter also takes care of the "tail" part of the buffer +// before entering the core loop, if any. The checksum is a sum so it +// allows us to commute operations. So we do do the "head" and "tail" +// first to finish at full speed in the body. Once we get the head and +// tail values, we feed them into the pipeline, very handy initialization. +// +// Of course we deal with the special case where the whole buffer fits +// into one 8 byte word. In this case we have only one entry in the pipeline. +// +// We use a (3+1)-stage pipeline in the loop to account for possible +// load latency and also to accomodate for head and tail. +// +// The end of the function deals with folding the checksum from 64bits +// down to 16bits taking care of the carry. +// +// This version avoids synchronization in the core loop by also using a +// pipeline for the accumulation of the checksum in result[]. +// +// p[] +// |---| +// 0| | r32 : new value loaded in pipeline +// |---| +// 1| | r33 : in transit data +// |---| +// 2| | r34 : current value to add to checksum +// |---| +// 3| | r35 : previous value added to checksum (previous iteration) +// |---| +// +// result[] +// |---| +// 0| | r36 : new checksum +// |---| +// 1| | r37 : previous value of checksum +// |---| +// 2| | r38 : final checksum when out of the loop (after 2 epilogue rots) +// |---| +// +// +// NOT YET DONE: +// - Take advantage of the MMI bandwidth to load more than 8byte per loop +// iteration +// - use the lfetch instruction to augment the chances of the data being in +// the cache when we need it. +// - Maybe another algorithm which would take care of the folding at the +// end in a different manner +// - Work with people more knowledgeable than me on the network stack +// to figure out if we could not split the function depending on the +// type of packet or alignment we get. Like the ip_fast_csum() routine +// where we know we have at least 20bytes worth of data to checksum. +// - Look at RFCs about checksums to see whether or not we can do better +// +// - Do a better job of handling small packets. +// +#define saved_pfs r11 +#define hmask r16 +#define tmask r17 +#define first r18 +#define firstval r19 +#define firstoff r20 +#define last r21 +#define lastval r22 +#define lastoff r23 +#define saved_lc r24 +#define saved_pr r25 +#define tmp1 r26 +#define tmp2 r27 +#define tmp3 r28 +#define carry r29 + +#define buf in0 +#define len in1 + + + .text + .psr abi64 + .psr lsb + .lsb + +// unsigned long do_csum(unsigned char *buf,int len) + + .align 32 + .global do_csum + .proc do_csum +do_csum: + alloc saved_pfs=ar.pfs,2,8,0,8 + + .rotr p[4], result[3] + mov ret0=r0 // in case we have zero length + cmp4.lt p0,p6=r0,len // check for zero length or negative (32bit len) + ;; // avoid WAW on CFM + mov tmp3=0x7 // a temporary mask/value + add tmp1=buf,len // last byte's address +(p6) br.ret.spnt.few rp // return if true (hope we can avoid that) + + and firstoff=7,buf // how many bytes off for first element + tbit.nz p10,p0=buf,0 // is buf an odd address ? + mov hmask=-1 // intialize head mask + ;; + + andcm first=buf,tmp3 // 8byte aligned down address of first element + mov tmask=-1 // initialize tail mask + adds tmp2=-1,tmp1 // last-1 + ;; + and lastoff=7,tmp1 // how many bytes off for last element + andcm last=tmp2,tmp3 // address of word containing last byte + mov saved_pr=pr // preserve predicates (rotation) + ;; + sub tmp3=last,first // tmp3=distance from first to last + cmp.eq p8,p9=last,first // everything fits in one word ? + sub tmp1=8,lastoff // complement to lastoff + + ld8 firstval=[first],8 // load,ahead of time, "first" word + shl tmp2=firstoff,3 // number of bits + ;; + and tmp1=7, tmp1 // make sure that if tmp1==8 -> tmp1=0 + +(p9) ld8 lastval=[last] // load,ahead of time, "last" word, if needed +(p8) mov lastval=r0 // we don't need lastval if first==last + mov result[1]=r0 // initialize result + ;; + + shl tmp1=tmp1,3 // number of bits + shl hmask=hmask,tmp2 // build head mask, mask off [0,firstoff[ + ;; + shr.u tmask=tmask,tmp1 // build tail mask, mask off ]8,lastoff] + mov saved_lc=ar.lc // save lc + ;; +(p8) and hmask=hmask,tmask // apply tail mask to head mask if 1 word only +(p9) and p[1]=lastval,tmask // mask last it as appropriate + shr.u tmp3=tmp3,3 // we do 8 bytes per loop + ;; + cmp.lt p6,p7=2,tmp3 // tmp3 > 2 ? + and p[2]=firstval,hmask // and mask it as appropriate + add tmp1=-2,tmp3 // -2 = -1 (br.ctop) -1 (last-first) + ;; + // XXX Fixme: not very nice initialization here + // + // Setup loop control registers: + // + // tmp3=0 (1 word) : lc=0, ec=2, p16=F + // tmp3=1 (2 words) : lc=0, ec=3, p16=F + // tmp3=2 (3 words) : lc=0, ec=4, p16=T + // tmp3>2 (4 or more): lc=tmp3-2, ec=4, p16=T + // + cmp.eq p8,p9=r0,tmp3 // tmp3 == 0 ? +(p6) mov ar.lc=tmp1 +(p7) mov ar.lc=0 + ;; + cmp.lt p6,p7=1,tmp3 // tmp3 > 1 ? +(p8) mov ar.ec=2 // we need the extra rotation on result[] +(p9) mov ar.ec=3 // hard not to set it twice sometimes + ;; + mov carry=r0 // initialize carry +(p6) mov ar.ec=4 +(p6) mov pr.rot=0xffffffffffff0000 // p16=T, p18=T + + cmp.ne p8,p0=r0,r0 // p8 is false + mov p[3]=r0 // make sure first compare fails +(p7) mov pr.rot=0xfffffffffffe0000 // p16=F, p18=T + ;; +1: +(p16) ld8 p[0]=[first],8 // load next +(p8) adds carry=1,carry // add carry on prev_prev_value +(p18) add result[0]=result[1],p[2] // new_res = prev_res + cur_val + cmp.ltu p8,p0=result[1],p[3] // p8= prev_result < prev_val + br.ctop.dptk.few 1b // loop until lc--==0 + ;; // RAW on carry when loop exits + (p8) adds carry=1,carry;; // correct for carry on prev_value + add result[2]=carry,result[2];; // add carry to final result + cmp.ltu p6,p7=result[2], carry // check for new carry + ;; +(p6) adds result[2]=1,result[1] // correct if required + movl tmp3=0xffffffff + ;; + // XXX Fixme + // + // now fold 64 into 16 bits taking care of carry + // that's not very good because it has lots of sequentiality + // + and tmp1=result[2],tmp3 + shr.u tmp2=result[2],32 + ;; + add result[2]=tmp1,tmp2 + shr.u tmp3=tmp3,16 + ;; + and tmp1=result[2],tmp3 + shr.u tmp2=result[2],16 + ;; + add result[2]=tmp1,tmp2 + ;; + and tmp1=result[2],tmp3 + shr.u tmp2=result[2],16 + ;; + add result[2]=tmp1,tmp2 + ;; + and tmp1=result[2],tmp3 + shr.u tmp2=result[2],16 + ;; + add ret0=tmp1,tmp2 + mov pr=saved_pr,0xffffffffffff0000 + ;; + // if buf was odd then swap bytes + mov ar.pfs=saved_pfs // restore ar.ec +(p10) mux1 ret0=ret0,@rev // reverse word + ;; + mov ar.lc=saved_lc +(p10) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes + br.ret.sptk.few rp diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/flush.S linux/arch/ia64/lib/flush.S --- v2.3.42/linux/arch/ia64/lib/flush.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/flush.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,37 @@ +/* + * Cache flushing routines. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + */ +#include + + .text + .psr abi64 + .psr lsb + .lsb + + .align 16 + .global ia64_flush_icache_page + .proc ia64_flush_icache_page +ia64_flush_icache_page: + alloc r2=ar.pfs,1,0,0,0 + mov r3=ar.lc // save ar.lc + mov r8=PAGE_SIZE/64-1 // repeat/until loop + ;; + mov ar.lc=r8 + add r8=32,in0 + ;; +.Loop1: fc in0 // issuable on M0 only + add in0=64,in0 + fc r8 + add r8=64,r8 + br.cloop.sptk.few .Loop1 + ;; + sync.i + ;; + srlz.i + ;; + mov ar.lc=r3 // restore ar.lc + br.ret.sptk.few rp + .endp ia64_flush_icache_page diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/idiv.S linux/arch/ia64/lib/idiv.S --- v2.3.42/linux/arch/ia64/lib/idiv.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/idiv.S Tue Feb 8 12:01:59 2000 @@ -0,0 +1,158 @@ +/* + * Integer division routine. + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + */ +/* Simple integer division. It uses the straight forward division + algorithm. This may not be the absolutely fastest way to do it, + but it's not horrible either. According to ski, the worst case + scenario of dividing 0xffffffffffffffff by 1 takes 133 cycles. + + An alternative would be to use an algorithm similar to the + floating point division algorithm (Newton-Raphson iteration), + but that approach is rather tricky (one has to be very careful + to get the last bit right...). + + While this algorithm is straight-forward, it does use a couple + of neat ia-64 specific tricks: + + - it uses the floating point unit to determine the initial + shift amount (shift = floor(ld(x)) - floor(ld(y))) + + - it uses predication to avoid a branch in the case where + x < y (this is what p8 is used for) + + - it uses rotating registers and the br.ctop branch to + implement a software-pipelined loop that's unrolled + twice (without any code expansion!) + + - the code is relatively well scheduled to avoid unnecessary + nops while maximizing parallelism +*/ + +#include + + .text + .psr abi64 +#ifdef __BIG_ENDIAN__ + .psr msb + .msb +#else + .psr lsb + .lsb +#endif + +#ifdef MODULO +# define OP mod +# define Q r9 +# define R r8 +#else +# define OP div +# define Q r8 +# define R r9 +#endif + +#ifdef SINGLE +# define PREC si +#else +# define PREC di +#endif + +#ifdef UNSIGNED +# define SGN u +# define INT_TO_FP(a,b) fma.s0 a=b,f1,f0 +# define FP_TO_INT(a,b) fcvt.fxu.trunc.s0 a=b +#else +# define SGN +# define INT_TO_FP(a,b) fcvt.xf a=b +# define FP_TO_INT(a,b) fcvt.fx.trunc.s0 a=b +#endif + +#define PASTE1(a,b) a##b +#define PASTE(a,b) PASTE1(a,b) +#define NAME PASTE(PASTE(__,SGN),PASTE(OP,PASTE(PREC,3))) + + .align 32 + .global NAME + .proc NAME +NAME: + + alloc r2=ar.pfs,2,6,0,8 + mov r18=pr +#ifdef SINGLE +# ifdef UNSIGNED + zxt4 in0=in0 + zxt4 in1=in1 +# else + sxt4 in0=in0 + sxt4 in1=in1 +# endif + ;; +#endif + +#ifndef UNSIGNED + cmp.lt p6,p0=in0,r0 // x negative? + cmp.lt p7,p0=in1,r0 // y negative? + ;; +(p6) sub in0=r0,in0 // make x positive +(p7) sub in1=r0,in1 // ditto for y + ;; +#endif + + setf.sig f8=in0 + mov r3=ar.lc // save ar.lc + setf.sig f9=in1 + ;; + mov Q=0 // initialize q + mov R=in0 // stash away x in a static register + mov r16=1 // r16 = 1 + INT_TO_FP(f8,f8) + cmp.eq p8,p0=0,in0 // x==0? + cmp.eq p9,p0=0,in1 // y==0? + ;; + INT_TO_FP(f9,f9) +(p8) br.dpnt.few .L3 +(p9) break __IA64_BREAK_KDB // attempted division by zero (should never happen) + mov ar.ec=r0 // epilogue count = 0 + ;; + getf.exp r14=f8 // r14 = exponent of x + getf.exp r15=f9 // r15 = exponent of y + mov ar.lc=r0 // loop count = 0 + ;; + sub r17=r14,r15 // r17 = (exp of x - exp y) = shift amount + cmp.ge p8,p0=r14,r15 + ;; + + .rotr y[2], mask[2] // in0 and in1 may no longer be valid after + // the first write to a rotating register! + +(p8) shl y[1]=in1,r17 // y[1] = y<= y[1]) +(p8) shr.u mask[0]=mask[1],1 // prepare mask[0] and y[0] for next +(p8) shr.u y[0]=y[1],1 // iteration + ;; +(p9) sub R=R,y[1] // if (x >= y[1]), subtract y[1] from x +(p9) add Q=Q,mask[1] // and set corresponding bit in q (Q) + br.ctop.dptk.few .L1 // repeated unless ar.lc-- == 0 + ;; +.L2: +#ifndef UNSIGNED +# ifdef MODULO +(p6) sub R=r0,R // set sign of remainder according to x +# else +(p6) sub Q=r0,Q // set sign of quotient + ;; +(p7) sub Q=r0,Q +# endif +#endif +.L3: + mov ar.pfs=r2 // restore ar.pfs + mov ar.lc=r3 // restore ar.lc + mov pr=r18,0xffffffffffff0000 // restore p16-p63 + br.ret.sptk.few rp diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/memset.S linux/arch/ia64/lib/memset.S --- v2.3.42/linux/arch/ia64/lib/memset.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/memset.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,111 @@ +/* + * + * Optimized version of the standard memset() function + * + * Return: none + * + * + * Inputs: + * in0: address of buffer + * in1: byte value to use for storing + * in2: length of the buffer + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + */ + + +// arguments +// +#define buf r32 +#define val r33 +#define len r34 + +// +// local registers +// +#define saved_pfs r14 +#define cnt r18 +#define buf2 r19 +#define saved_lc r20 +#define saved_pr r21 +#define tmp r22 + + .text + .psr abi64 + .psr lsb + + .align 16 + .global memset + .proc memset + +memset: + alloc saved_pfs=ar.pfs,3,0,0,0 // cnt is sink here + cmp.eq p8,p0=r0,len // check for zero length + mov saved_lc=ar.lc // preserve ar.lc (slow) + ;; + adds tmp=-1,len // br.ctop is repeat/until + tbit.nz p6,p0=buf,0 // odd alignment +(p8) br.ret.spnt.few rp + + cmp.lt p7,p0=16,len // if len > 16 then long memset + mux1 val=val,@brcst // prepare value +(p7) br.cond.dptk.few long_memset + ;; + mov ar.lc=tmp // initialize lc for small count + ;; // avoid RAW and WAW on ar.lc +1: // worst case 15 cyles, avg 8 cycles + st1 [buf]=val,1 + br.cloop.dptk.few 1b + ;; // avoid RAW on ar.lc + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + br.ret.sptk.few rp // end of short memset + + // at this point we know we have more than 16 bytes to copy + // so we focus on alignment +long_memset: +(p6) st1 [buf]=val,1 // 1-byte aligned +(p6) adds len=-1,len;; // sync because buf is modified + tbit.nz p6,p0=buf,1 + ;; +(p6) st2 [buf]=val,2 // 2-byte aligned +(p6) adds len=-2,len;; + tbit.nz p6,p0=buf,2 + ;; +(p6) st4 [buf]=val,4 // 4-byte aligned +(p6) adds len=-4,len;; + tbit.nz p6,p0=buf,3 + ;; +(p6) st8 [buf]=val,8 // 8-byte aligned +(p6) adds len=-8,len;; + shr.u cnt=len,4 // number of 128-bit (2x64bit) words + ;; + cmp.eq p6,p0=r0,cnt + adds tmp=-1,cnt +(p6) br.cond.dpnt.few .dotail // we have less than 16 bytes left + ;; + adds buf2=8,buf // setup second base pointer + mov ar.lc=tmp + ;; +2: // 16bytes/iteration + st8 [buf]=val,16 + st8 [buf2]=val,16 + br.cloop.dptk.few 2b + ;; +.dotail: // tail correction based on len only + tbit.nz p6,p0=len,3 + ;; +(p6) st8 [buf]=val,8 // at least 8 bytes + tbit.nz p6,p0=len,2 + ;; +(p6) st4 [buf]=val,4 // at least 4 bytes + tbit.nz p6,p0=len,1 + ;; +(p6) st2 [buf]=val,2 // at least 2 bytes + tbit.nz p6,p0=len,0 + mov ar.lc=saved_lc + ;; +(p6) st1 [buf]=val // only 1 byte left + br.ret.dptk.few rp + .endp diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S --- v2.3.42/linux/arch/ia64/lib/strlen.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/strlen.S Wed Feb 9 19:45:43 2000 @@ -0,0 +1,197 @@ +/* + * + * Optimized version of the standard strlen() function + * + * + * Inputs: + * in0 address of string + * + * Outputs: + * ret0 the number of characters in the string (0 if empty string) + * does not count the \0 + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + * + * 09/24/99 S.Eranian add speculation recovery code + */ + +// +// +// This is an enhanced version of the basic strlen. it includes a combination +// of compute zero index (czx), parallel comparisons, speculative loads and +// loop unroll using rotating registers. +// +// General Ideas about the algorithm: +// The goal is to look at the string in chunks of 8 bytes. +// so we need to do a few extra checks at the beginning because the +// string may not be 8-byte aligned. In this case we load the 8byte +// quantity which includes the start of the string and mask the unused +// bytes with 0xff to avoid confusing czx. +// We use speculative loads and software pipelining to hide memory +// latency and do read ahead safely. This way we defer any exception. +// +// Because we don't want the kernel to be relying on particular +// settings of the DCR register, we provide recovery code in case +// speculation fails. The recovery code is going to "redo" the work using +// only normal loads. If we still get a fault then we generate a +// kernel panic. Otherwise we return the strlen as usual. +// +// The fact that speculation may fail can be caused, for instance, by +// the DCR.dm bit being set. In this case TLB misses are deferred, i.e., +// a NaT bit will be set if the translation is not present. The normal +// load, on the other hand, will cause the translation to be inserted +// if the mapping exists. +// +// It should be noted that we execute recovery code only when we need +// to use the data that has been speculatively loaded: we don't execute +// recovery code on pure read ahead data. +// +// Remarks: +// - the cmp r0,r0 is used as a fast way to initialize a predicate +// register to 1. This is required to make sure that we get the parallel +// compare correct. +// +// - we don't use the epilogue counter to exit the loop but we need to set +// it to zero beforehand. +// +// - after the loop we must test for Nat values because neither the +// czx nor cmp instruction raise a NaT consumption fault. We must be +// careful not to look too far for a Nat for which we don't care. +// For instance we don't need to look at a NaT in val2 if the zero byte +// was in val1. +// +// - Clearly performance tuning is required. +// +// +// +#define saved_pfs r11 +#define tmp r10 +#define base r16 +#define orig r17 +#define saved_pr r18 +#define src r19 +#define mask r20 +#define val r21 +#define val1 r22 +#define val2 r23 + + + .text + .psr abi64 + .psr lsb + .lsb + + .align 32 + .global strlen + .proc strlen +strlen: + alloc saved_pfs=ar.pfs,11,0,0,8 // rotating must be multiple of 8 + + .rotr v[2], w[2] // declares our 4 aliases + + extr.u tmp=in0,0,3 // tmp=least significant 3 bits + mov orig=in0 // keep trackof initial byte address + dep src=0,in0,0,3 // src=8byte-aligned in0 address + mov saved_pr=pr // preserve predicates (rotation) + ;; + ld8 v[1]=[src],8 // must not speculate: can fail here + shl tmp=tmp,3 // multiply by 8bits/byte + mov mask=-1 // our mask + ;; + ld8.s w[1]=[src],8 // speculatively load next + cmp.eq p6,p0=r0,r0 // sets p6 to true for cmp.and + sub tmp=64,tmp // how many bits to shift our mask on the right + ;; + shr.u mask=mask,tmp // zero enough bits to hold v[1] valuable part + mov ar.ec=r0 // clear epilogue counter (saved in ar.pfs) + ;; + add base=-16,src // keep track of aligned base + or v[1]=v[1],mask // now we have a safe initial byte pattern + ;; +1: + ld8.s v[0]=[src],8 // speculatively load next + czx1.r val1=v[1] // search 0 byte from right + czx1.r val2=w[1] // search 0 byte from right following 8bytes + ;; + ld8.s w[0]=[src],8 // speculatively load next to next + cmp.eq.and p6,p0=8,val1 // p6 = p6 and val1==8 + cmp.eq.and p6,p0=8,val2 // p6 = p6 and mask==8 +(p6) br.wtop.dptk.few 1b // loop until p6 == 0 + ;; + // + // We must return try the recovery code iff + // val1_is_nat || (val1==8 && val2_is_nat) + // + // XXX Fixme + // - there must be a better way of doing the test + // + cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) +#ifdef notyet + tnat.nz p6,p7=val1 // test NaT on val1 +#else + tnat.z p7,p6=val1 // test NaT on val1 +#endif +(p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT + ;; + // + // if we come here p7 is true, i.e., initialized for // cmp + // + cmp.eq.and p7,p0=8,val1// val1==8? + tnat.nz.and p7,p0=val2 // test NaT if val2 +(p7) br.cond.spnt.few recover// jump to recovery if val2 is NaT + ;; +(p8) mov val1=val2 // the other test got us out of the loop +(p8) adds src=-16,src // correct position when 3 ahead +(p9) adds src=-24,src // correct position when 4 ahead + ;; + sub ret0=src,orig // distance from base + sub tmp=8,val1 // which byte in word + mov pr=saved_pr,0xffffffffffff0000 + ;; + sub ret0=ret0,tmp // adjust + mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what + br.ret.sptk.few rp // end of normal execution + + // + // Outlined recovery code when speculation failed + // + // This time we don't use speculation and rely on the normal exception + // mechanism. that's why the loop is not as good as the previous one + // because read ahead is not possible + // + // IMPORTANT: + // Please note that in the case of strlen() as opposed to strlen_user() + // we don't use the exception mechanism, as this function is not + // supposed to fail. If that happens it means we have a bug and the + // code will cause of kernel fault. + // + // XXX Fixme + // - today we restart from the beginning of the string instead + // of trying to continue where we left off. + // +recover: + ld8 val=[base],8 // will fail if unrecoverable fault + ;; + or val=val,mask // remask first bytes + cmp.eq p0,p6=r0,r0 // nullify first ld8 in loop + ;; + // + // ar.ec is still zero here + // +2: +(p6) ld8 val=[base],8 // will fail if unrecoverable fault + ;; + czx1.r val1=val // search 0 byte from right + ;; + cmp.eq p6,p0=8,val1 // val1==8 ? +(p6) br.wtop.dptk.few 2b // loop until p6 == 0 + sub ret0=base,orig // distance from base + sub tmp=8,val1 + mov pr=saved_pr,0xffffffffffff0000 + ;; + sub ret0=ret0,tmp // length=now - back -1 + mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what + br.ret.sptk.few rp // end of sucessful recovery code + + .endp strlen diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/strlen_user.S linux/arch/ia64/lib/strlen_user.S --- v2.3.42/linux/arch/ia64/lib/strlen_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/strlen_user.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,213 @@ +/* + * Optimized version of the strlen_user() function + * + * Inputs: + * in0 address of buffer + * + * Outputs: + * ret0 0 in case of fault, strlen(buffer)+1 otherwise + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999 Stephane Eranian + * + * 01/19/99 S.Eranian heavily enhanced version (see details below) + * 09/24/99 S.Eranian added speculation recovery code + */ + +// +// int strlen_user(char *) +// ------------------------ +// Returns: +// - length of string + 1 +// - 0 in case an exception is raised +// +// This is an enhanced version of the basic strlen_user. it includes a +// combination of compute zero index (czx), parallel comparisons, speculative +// loads and loop unroll using rotating registers. +// +// General Ideas about the algorithm: +// The goal is to look at the string in chunks of 8 bytes. +// so we need to do a few extra checks at the beginning because the +// string may not be 8-byte aligned. In this case we load the 8byte +// quantity which includes the start of the string and mask the unused +// bytes with 0xff to avoid confusing czx. +// We use speculative loads and software pipelining to hide memory +// latency and do read ahead safely. This way we defer any exception. +// +// Because we don't want the kernel to be relying on particular +// settings of the DCR register, we provide recovery code in case +// speculation fails. The recovery code is going to "redo" the work using +// only normal loads. If we still get a fault then we return an +// error (ret0=0). Otherwise we return the strlen+1 as usual. +// The fact that speculation may fail can be caused, for instance, by +// the DCR.dm bit being set. In this case TLB misses are deferred, i.e., +// a NaT bit will be set if the translation is not present. The normal +// load, on the other hand, will cause the translation to be inserted +// if the mapping exists. +// +// It should be noted that we execute recovery code only when we need +// to use the data that has been speculatively loaded: we don't execute +// recovery code on pure read ahead data. +// +// Remarks: +// - the cmp r0,r0 is used as a fast way to initialize a predicate +// register to 1. This is required to make sure that we get the parallel +// compare correct. +// +// - we don't use the epilogue counter to exit the loop but we need to set +// it to zero beforehand. +// +// - after the loop we must test for Nat values because neither the +// czx nor cmp instruction raise a NaT consumption fault. We must be +// careful not to look too far for a Nat for which we don't care. +// For instance we don't need to look at a NaT in val2 if the zero byte +// was in val1. +// +// - Clearly performance tuning is required. +// +// +// + +#define EX(y,x...) \ + .section __ex_table,"a"; \ + data4 @gprel(99f); \ + data4 y-99f; \ + .previous; \ +99: x + +#define saved_pfs r11 +#define tmp r10 +#define base r16 +#define orig r17 +#define saved_pr r18 +#define src r19 +#define mask r20 +#define val r21 +#define val1 r22 +#define val2 r23 + + + .text + .psr abi64 + .psr lsb + .lsb + + .align 32 + .global __strlen_user + .proc __strlen_user +__strlen_user: + alloc saved_pfs=ar.pfs,11,0,0,8 + + .rotr v[2], w[2] // declares our 4 aliases + + extr.u tmp=in0,0,3 // tmp=least significant 3 bits + mov orig=in0 // keep trackof initial byte address + dep src=0,in0,0,3 // src=8byte-aligned in0 address + mov saved_pr=pr // preserve predicates (rotation) + ;; + ld8.s v[1]=[src],8 // load the initial 8bytes (must speculate) + shl tmp=tmp,3 // multiply by 8bits/byte + mov mask=-1 // our mask + ;; + ld8.s w[1]=[src],8 // load next 8 bytes in 2nd pipeline + cmp.eq p6,p0=r0,r0 // sets p6 (required because of // cmp.and) + sub tmp=64,tmp // how many bits to shift our mask on the right + ;; + shr.u mask=mask,tmp // zero enough bits to hold v[1] valuable part + mov ar.ec=r0 // clear epilogue counter (saved in ar.pfs) + ;; + add base=-16,src // keep track of aligned base + chk.s v[1], recover // if already NaT, then directly skip to recover + or v[1]=v[1],mask // now we have a safe initial byte pattern + ;; +1: + ld8.s v[0]=[src],8 // speculatively load next + czx1.r val1=v[1] // search 0 byte from right + czx1.r val2=w[1] // search 0 byte from right following 8bytes + ;; + ld8.s w[0]=[src],8 // speculatively load next to next + cmp.eq.and p6,p0=8,val1 // p6 = p6 and val1==8 + cmp.eq.and p6,p0=8,val2 // p6 = p6 and mask==8 +(p6) br.wtop.dptk.few 1b // loop until p6 == 0 + ;; + // + // We must return try the recovery code iff + // val1_is_nat || (val1==8 && val2_is_nat) + // + // XXX Fixme + // - there must be a better way of doing the test + // + cmp.eq p8,p9=8,val1 // p6 = val1 had zero (disambiguate) +#ifdef notyet + tnat.nz p6,p7=val1 // test NaT on val1 +#else + tnat.z p7,p6=val1 // test NaT on val1 +#endif +(p6) br.cond.spnt.few recover// jump to recovery if val1 is NaT + ;; + // + // if we come here p7 is true, i.e., initialized for // cmp + // + cmp.eq.and p7,p0=8,val1// val1==8? + tnat.nz.and p7,p0=val2 // test NaT if val2 +(p7) br.cond.spnt.few recover// jump to recovery if val2 is NaT + ;; +(p8) mov val1=val2 // val2 contains the value +(p8) adds src=-16,src // correct position when 3 ahead +(p9) adds src=-24,src // correct position when 4 ahead + ;; + sub ret0=src,orig // distance from origin + sub tmp=7,val1 // 7=8-1 because this strlen returns strlen+1 + mov pr=saved_pr,0xffffffffffff0000 + ;; + sub ret0=ret0,tmp // length=now - back -1 + mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what + br.ret.sptk.few rp // end of normal execution + + // + // Outlined recovery code when speculation failed + // + // This time we don't use speculation and rely on the normal exception + // mechanism. that's why the loop is not as good as the previous one + // because read ahead is not possible + // + // XXX Fixme + // - today we restart from the beginning of the string instead + // of trying to continue where we left off. + // +recover: + EX(.Lexit1, ld8 val=[base],8) // load the initial bytes + ;; + or val=val,mask // remask first bytes + cmp.eq p0,p6=r0,r0 // nullify first ld8 in loop + ;; + // + // ar.ec is still zero here + // +2: + EX(.Lexit1, (p6) ld8 val=[base],8) + ;; + czx1.r val1=val // search 0 byte from right + ;; + cmp.eq p6,p0=8,val1 // val1==8 ? +(p6) br.wtop.dptk.few 2b // loop until p6 == 0 + ;; + sub ret0=base,orig // distance from base + sub tmp=7,val1 // 7=8-1 because this strlen returns strlen+1 + mov pr=saved_pr,0xffffffffffff0000 + ;; + sub ret0=ret0,tmp // length=now - back -1 + mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what + br.ret.sptk.few rp // end of sucessful recovery code + + // + // We failed even on the normal load (called from exception handler) + // +.Lexit1: + mov ret0=0 + mov pr=saved_pr,0xffffffffffff0000 + mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what + br.ret.sptk.few rp + + .endp __strlen_user diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/strncpy_from_user.S linux/arch/ia64/lib/strncpy_from_user.S --- v2.3.42/linux/arch/ia64/lib/strncpy_from_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/strncpy_from_user.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,53 @@ +/* + * Just like strncpy() except for the return value. If no fault occurs during + * the copying, the number of bytes copied is returned. If a fault occurs, + * -EFAULT is returned. + * + * Inputs: + * in0: address of destination buffer + * in1: address of string to be copied + * in2: length of buffer in bytes + * Outputs: + * r8: -EFAULT in case of fault or number of bytes copied if no fault + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + */ + +#define EX(x...) \ +99: x; \ + .section __ex_table,"a"; \ + data4 @gprel(99b); \ + data4 .Lexit-99b; \ + .previous + + .text + .psr abi64 + .psr lsb + .lsb + + .align 32 + .global __strncpy_from_user + .proc __strncpy_from_user +__strncpy_from_user: + alloc r11=ar.pfs,3,0,0,0 + mov r9=in1 + add r10=in1,in2 + + // XXX braindead copy loop---this needs to be optimized +.Loop1: + EX(ld1 r8=[in1],1) + ;; + st1 [in0]=r8,1 + cmp.ltu p6,p0=in1,r10 + ;; +(p6) cmp.ne.and p6,p0=r8,r0 + ;; +(p6) br.cond.dpnt.few .Loop1 + +1: sub r8=in1,r9 // length of string (including NUL character) +.Lexit: + mov ar.pfs=r11 + br.ret.sptk.few rp + + .endp __strncpy_from_user diff -u --recursive --new-file v2.3.42/linux/arch/ia64/lib/strnlen_user.S linux/arch/ia64/lib/strnlen_user.S --- v2.3.42/linux/arch/ia64/lib/strnlen_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/lib/strnlen_user.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,55 @@ +/* + * Returns 0 if exception before NUL or reaching the supplied limit (N), + * a value greater than N if the string is longer than the limit, else + * strlen. + * + * Inputs: + * in0: address of buffer + * in1: string length limit N + * Outputs: + * r8: 0 in case of fault, strlen(buffer)+1 otherwise + * + * Copyright (C) 1999 David Mosberger-Tang + */ + +/* If a fault occurs, r8 gets set to -EFAULT and r9 gets cleared. */ +#define EX(x...) \ + .section __ex_table,"a"; \ + data4 @gprel(99f); \ + data4 (.Lexit-99f)|1; \ + .previous \ +99: x; + + .text + .psr abi64 + .psr lsb + .lsb + + .align 32 + .global __strnlen_user + .proc __strnlen_user +__strnlen_user: + alloc r2=ar.pfs,2,0,0,0 + mov r16=ar.lc // preserve ar.lc + add r3=-1,in1 + ;; + mov ar.lc=r3 + mov r9=0 + + // XXX braindead strlen loop---this needs to be optimized +.Loop1: + EX(ld1 r8=[in0],1) + add r9=1,r9 + ;; + cmp.eq p6,p0=r8,r0 +(p6) br.dpnt.few .Lexit + br.cloop.dptk.few .Loop1 + + add r9=1,in1 // NUL not found---return N+1 + ;; +.Lexit: + mov r8=r9 + mov ar.lc=r16 // restore ar.lc + br.ret.sptk.few rp + + .endp __strnlen_user diff -u --recursive --new-file v2.3.42/linux/arch/ia64/mm/Makefile linux/arch/ia64/mm/Makefile --- v2.3.42/linux/arch/ia64/mm/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/mm/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,14 @@ +# +# Makefile for the ia64-specific parts of the memory manager. +# +# 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 := mm.o +#O_OBJS := ioremap.o +O_OBJS := init.o fault.o tlb.o extable.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/mm/extable.c linux/arch/ia64/mm/extable.c --- v2.3.42/linux/arch/ia64/mm/extable.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/mm/extable.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,68 @@ +/* + * Kernel exception handling table support. Derived from arch/alpha/mm/extable.c. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + */ + +#include +#include +#include + +extern const struct exception_table_entry __start___ex_table[]; +extern const struct exception_table_entry __stop___ex_table[]; + +static inline const struct exception_table_entry * +search_one_table (const struct exception_table_entry *first, + const struct exception_table_entry *last, + signed long value) +{ + /* Abort early if the search value is out of range. */ + if (value != (signed int)value) + return 0; + + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + /* + * We know that first and last are both kernel virtual + * pointers (region 7) so first+last will cause an + * overflow. We fix that by calling __va() on the + * result, which will ensure that the top two bits get + * set again. + */ + mid = (void *) __va((((__u64) first + (__u64) last)/2/sizeof(*mid))*sizeof(*mid)); + diff = mid->addr - value; + if (diff == 0) + return mid; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return 0; +} + +register unsigned long gp __asm__("gp"); + +const struct exception_table_entry * +search_exception_table (unsigned long addr) +{ +#ifndef CONFIG_MODULE + /* There is only the kernel to search. */ + return search_one_table(__start___ex_table, __stop___ex_table - 1, addr - gp); +#else + struct exception_table_entry *ret; + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; + + for (mp = module_list; mp ; mp = mp->next) { + if (!mp->ex_table_start) + continue; + ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp); + if (ret) + return ret; + } + return 0; +#endif +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c --- v2.3.42/linux/arch/ia64/mm/fault.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/mm/fault.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,164 @@ +/* + * MMU fault handling support. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern void die_if_kernel (char *, struct pt_regs *, long); + +/* + * This routine is analogous to expand_stack() but instead grows the + * register backing store (which grows towards higher addresses). + * Since the register backing store is access sequentially, we + * disallow growing the RBS by more than a page at a time. Note that + * the VM_GROWSUP flag can be set on any VM area but that's fine + * because the total process size is still limited by RLIMIT_STACK and + * RLIMIT_AS. + */ +static inline long +expand_backing_store (struct vm_area_struct *vma, unsigned long address) +{ + unsigned long grow; + + grow = PAGE_SIZE >> PAGE_SHIFT; + if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur + || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)) + return -ENOMEM; + vma->vm_end += PAGE_SIZE; + vma->vm_mm->total_vm += grow; + if (vma->vm_flags & VM_LOCKED) + vma->vm_mm->locked_vm += grow; + return 0; +} + +void +ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) +{ + struct mm_struct *mm = current->mm; + const struct exception_table_entry *fix; + struct vm_area_struct *vma, *prev_vma; + struct siginfo si; + int signal = SIGSEGV; + unsigned long mask; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || !mm) + goto no_context; + + down(&mm->mmap_sem); + + vma = find_vma_prev(mm, address, &prev_vma); + if (!vma) + goto bad_area; + + /* find_vma_prev() returns vma such that address < vma->vm_end or NULL */ + if (address < vma->vm_start) + goto check_expansion; + + good_area: + /* OK, we've got a good vm_area for this memory area. Check the access permissions: */ + +# define VM_READ_BIT 0 +# define VM_WRITE_BIT 1 +# define VM_EXEC_BIT 2 + +# if (((1 << VM_READ_BIT) != VM_READ || (1 << VM_WRITE_BIT) != VM_WRITE) \ + || (1 << VM_EXEC_BIT) != VM_EXEC) +# error File is out of sync with . Pleaes update. +# endif + + mask = ( (((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT) + | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT) + | (((isr >> IA64_ISR_R_BIT) & 1UL) << VM_READ_BIT)); + + if ((vma->vm_flags & mask) != mask) + goto bad_area; + + /* + * If for any reason at all we couldn't handle the fault, make + * sure we exit gracefully rather than endlessly redo the + * fault. + */ + if (!handle_mm_fault(current, vma, address, (isr & IA64_ISR_W) != 0)) { + /* + * We ran out of memory, or some other thing happened + * to us that made us unable to handle the page fault + * gracefully. + */ + signal = SIGBUS; + goto bad_area; + } + up(&mm->mmap_sem); + return; + + check_expansion: + if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) { + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, address)) + goto bad_area; + } else if (expand_backing_store(prev_vma, address)) + goto bad_area; + goto good_area; + + bad_area: + up(&mm->mmap_sem); + if (isr & IA64_ISR_SP) { + /* + * This fault was due to a speculative load set the + * "ed" bit in the psr to ensure forward progress + * (target register will get a NaT). + */ + ia64_psr(regs)->ed = 1; + return; + } + if (user_mode(regs)) { +#if 0 +printk("%s(%d): segfault accessing %lx\n", current->comm, current->pid, address); +show_regs(regs); +#endif + si.si_signo = signal; + si.si_errno = 0; + si.si_code = SI_KERNEL; + si.si_addr = (void *) address; + force_sig_info(SIGSEGV, &si, current); + return; + } + + no_context: + fix = search_exception_table(regs->cr_iip); + if (fix) { + regs->r8 = -EFAULT; + if (fix->skip & 1) { + regs->r9 = 0; + } + regs->cr_iip += ((long) fix->skip) & ~15; + regs->cr_ipsr &= ~IA64_PSR_RI; /* clear exception slot number */ + return; + } + + /* + * Oops. The kernel tried to access some bad page. We'll have + * to terminate things with extreme prejudice. + */ + printk(KERN_ALERT "Unable to handle kernel paging request at " + "virtual address %016lx\n", address); + die_if_kernel("Oops", regs, isr); + do_exit(SIGKILL); + return; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c --- v2.3.42/linux/arch/ia64/mm/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/mm/init.c Wed Feb 9 20:08:09 2000 @@ -0,0 +1,461 @@ +/* + * Initialize MMU support. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* References to section boundaries: */ +extern char _stext, _etext, _edata, __init_begin, __init_end; + +/* + * These are allocated in head.S so that we get proper page alignment. + * If you change the size of these then change head.S as well. + */ +extern char empty_bad_page[PAGE_SIZE]; +extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; +extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; + +extern void ia64_tlb_init (void); + +static unsigned long totalram_pages; + +/* + * Fill in empty_bad_pmd_table with entries pointing to + * empty_bad_pte_table and return the address of this PMD table. + */ +static pmd_t * +get_bad_pmd_table (void) +{ + pmd_t v; + int i; + + pmd_set(&v, empty_bad_pte_table); + + for (i = 0; i < PTRS_PER_PMD; ++i) + empty_bad_pmd_table[i] = v; + + return empty_bad_pmd_table; +} + +/* + * Fill in empty_bad_pte_table with PTEs pointing to empty_bad_page + * and return the address of this PTE table. + */ +static pte_t * +get_bad_pte_table (void) +{ + pte_t v; + int i; + + set_pte(&v, pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED))); + + for (i = 0; i < PTRS_PER_PTE; ++i) + empty_bad_pte_table[i] = v; + + return empty_bad_pte_table; +} + +void +__handle_bad_pgd (pgd_t *pgd) +{ + pgd_ERROR(*pgd); + pgd_set(pgd, get_bad_pmd_table()); +} + +void +__handle_bad_pmd (pmd_t *pmd) +{ + pmd_ERROR(*pmd); + pmd_set(pmd, get_bad_pte_table()); +} + +/* + * Allocate and initialize an L3 directory page and set + * the L2 directory entry PMD to the newly allocated page. + */ +pte_t* +get_pte_slow (pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + /* everything A-OK */ + clear_page(pte); + pmd_set(pmd, pte); + return pte + offset; + } + pmd_set(pmd, get_bad_pte_table()); + return NULL; + } + free_page((unsigned long) pte); + if (pmd_bad(*pmd)) { + __handle_bad_pmd(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +int +do_check_pgt_cache (int low, int high) +{ + int freed = 0; + + if (pgtable_cache_size > high) { + do { + if (pgd_quicklist) + free_page((unsigned long)get_pgd_fast()), ++freed; + if (pmd_quicklist) + free_page((unsigned long)get_pmd_fast()), ++freed; + if (pte_quicklist) + free_page((unsigned long)get_pte_fast()), ++freed; + } while (pgtable_cache_size > low); + } + return freed; +} + +/* + * This performs some platform-dependent address space initialization. + * On IA-64, we want to setup the VM area for the register backing + * store (which grows upwards) and install the gateway page which is + * used for signal trampolines, etc. + */ +void +ia64_init_addr_space (void) +{ + struct vm_area_struct *vma; + + /* + * If we're out of memory and kmem_cache_alloc() returns NULL, + * we simply ignore the problem. When the process attempts to + * write to the register backing store for the first time, it + * will get a SEGFAULT in this case. + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + vma->vm_mm = current->mm; + vma->vm_start = IA64_RBS_BOT; + vma->vm_end = vma->vm_start + PAGE_SIZE; + vma->vm_page_prot = PAGE_COPY; + vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; + vma->vm_ops = NULL; + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + insert_vm_struct(current->mm, vma); + } +} + +void +free_initmem (void) +{ + unsigned long addr; + + addr = (unsigned long) &__init_begin; + for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) { + clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags); + set_page_count(&mem_map[MAP_NR(addr)], 1); + free_page(addr); + ++totalram_pages; + } + printk ("Freeing unused kernel memory: %ldkB freed\n", + (&__init_end - &__init_begin) >> 10); +} + +void +si_meminfo (struct sysinfo *val) +{ + val->totalram = totalram_pages; + val->sharedram = 0; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = 0; + val->freehigh = 0; + val->mem_unit = PAGE_SIZE; + return; +} + +void +show_mem (void) +{ + int i,free = 0,total = 0,reserved = 0; + int shared = 0, cached = 0; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!page_count(mem_map + i)) + free++; + else + shared += page_count(mem_map + i) - 1; + } + printk("%d pages of RAM\n", total); + printk("%d reserved pages\n", reserved); + printk("%d pages shared\n", shared); + printk("%d pages swap cached\n", cached); + printk("%ld pages in page table cache\n", pgtable_cache_size); + show_buffers(); +} + +/* + * This is like put_dirty_page() but installs a clean page with PAGE_GATE protection + * (execute-only, typically). + */ +struct page * +put_gate_page (struct page *page, unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + if (!PageReserved(page)) + printk("put_gate_page: gate page at 0x%lx not in reserved memory\n", + page_address(page)); + pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ + pmd = pmd_alloc(pgd, address); + if (!pmd) { + __free_page(page); + oom(current); + return 0; + } + pte = pte_alloc(pmd, address); + if (!pte) { + __free_page(page); + oom(current); + return 0; + } + if (!pte_none(*pte)) { + pte_ERROR(*pte); + __free_page(page); + return 0; + } + flush_page_to_ram(page); + set_pte(pte, page_pte_prot(page, PAGE_GATE)); + /* no need for flush_tlb */ + return page; +} + +void __init +ia64_rid_init (void) +{ + unsigned long flags, rid, pta; + + /* Set up the kernel identity mappings (regions 6 & 7) and the vmalloc area (region 5): */ + ia64_clear_ic(flags); + + rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); + ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2)); + + rid = ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET); + ia64_set_rr(PAGE_OFFSET, (rid << 8) | (_PAGE_SIZE_256M << 2)); + + rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); + ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); + + __restore_flags(flags); + + /* + * Check if the virtually mapped linear page table (VMLPT) + * overlaps with a mapped address space. The IA-64 + * architecture guarantees that at least 50 bits of virtual + * address space are implemented but if we pick a large enough + * page size (e.g., 64KB), the VMLPT is big enough that it + * will overlap with the upper half of the kernel mapped + * region. I assume that once we run on machines big enough + * to warrant 64KB pages, IMPL_VA_MSB will be significantly + * bigger, so we can just adjust the number below to get + * things going. Alternatively, we could truncate the upper + * half of each regions address space to not permit mappings + * that would overlap with the VMLPT. --davidm 99/11/13 + */ +# define ld_pte_size 3 +# define ld_max_addr_space_pages 3*(PAGE_SHIFT - ld_pte_size) /* max # of mappable pages */ +# define ld_max_addr_space_size (ld_max_addr_space_pages + PAGE_SHIFT) +# define ld_max_vpt_size (ld_max_addr_space_pages + ld_pte_size) +# define POW2(n) (1ULL << (n)) +# define IMPL_VA_MSB 50 + if (POW2(ld_max_addr_space_size - 1) + POW2(ld_max_vpt_size) > POW2(IMPL_VA_MSB)) + panic("mm/init: overlap between virtually mapped linear page table and " + "mapped kernel space!"); + pta = POW2(61) - POW2(IMPL_VA_MSB); + /* + * Set the (virtually mapped linear) page table address. Bit + * 8 selects between the short and long format, bits 2-7 the + * size of the table, and bit 0 whether the VHPT walker is + * enabled. + */ + ia64_set_pta(pta | (0<<8) | ((3*(PAGE_SHIFT-3)+3)<<2) | 1); +} + +#ifdef CONFIG_IA64_VIRTUAL_MEM_MAP + +static int +create_mem_map_page_table (u64 start, u64 end, void *arg) +{ + unsigned long address, start_page, end_page; + struct page *map_start, *map_end; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + void *page; + + map_start = mem_map + MAP_NR(start); + map_end = mem_map + MAP_NR(end); + + start_page = (unsigned long) map_start & PAGE_MASK; + end_page = PAGE_ALIGN((unsigned long) map_end); + + printk("[%lx,%lx) -> %lx-%lx\n", start, end, start_page, end_page); + + for (address = start_page; address < end_page; address += PAGE_SIZE) { + pgd = pgd_offset_k(address); + if (pgd_none(*pgd)) { + pmd = alloc_bootmem_pages(PAGE_SIZE); + clear_page(pmd); + pgd_set(pgd, pmd); + pmd += (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); + } else + pmd = pmd_offset(pgd, address); + if (pmd_none(*pmd)) { + pte = alloc_bootmem_pages(PAGE_SIZE); + clear_page(pte); + pmd_set(pmd, pte); + pte += (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + } else + pte = pte_offset(pmd, address); + + if (pte_none(*pte)) { + page = alloc_bootmem_pages(PAGE_SIZE); + clear_page(page); + set_pte(pte, mk_pte_phys(__pa(page), PAGE_KERNEL)); + } + } + return 0; +} + +#endif /* CONFIG_IA64_VIRTUAL_MEM_MAP */ + +/* + * Set up the page tables. + */ +void +paging_init (void) +{ + unsigned long max_dma, zones_size[MAX_NR_ZONES]; + + clear_page((void *) ZERO_PAGE_ADDR); + + ia64_rid_init(); + __flush_tlb_all(); + + /* initialize mem_map[] */ + + memset(zones_size, 0, sizeof(zones_size)); + + max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS); + if (max_low_pfn < max_dma) + zones_size[ZONE_DMA] = max_low_pfn; + else { + zones_size[ZONE_DMA] = max_dma; + zones_size[ZONE_NORMAL] = max_low_pfn - max_dma; + } + free_area_init(zones_size); +} + +static int +count_pages (u64 start, u64 end, void *arg) +{ + unsigned long *count = arg; + + *count += (end - start) >> PAGE_SHIFT; + return 0; +} + +static int +count_reserved_pages (u64 start, u64 end, void *arg) +{ + unsigned long num_reserved = 0; + unsigned long *count = arg; + struct page *pg; + + for (pg = mem_map + MAP_NR(start); pg < mem_map + MAP_NR(end); ++pg) + if (PageReserved(pg)) + ++num_reserved; + *count += num_reserved; + return 0; +} + +void +mem_init (void) +{ + extern char __start_gate_section[]; + long reserved_pages, codesize, datasize, initsize; + + if (!mem_map) + BUG(); + + num_physpages = 0; + efi_memmap_walk(count_pages, &num_physpages); + + max_mapnr = max_low_pfn; + high_memory = __va(max_low_pfn * PAGE_SIZE); + + ia64_tlb_init(); + + totalram_pages += free_all_bootmem(); + + reserved_pages = 0; + efi_memmap_walk(count_reserved_pages, &reserved_pages); + + codesize = (unsigned long) &_etext - (unsigned long) &_stext; + datasize = (unsigned long) &_edata - (unsigned long) &_etext; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + + printk("Memory: %luk/%luk available (%luk code, %luk reserved, %luk data, %luk init)\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT - 10), + max_mapnr << (PAGE_SHIFT - 10), codesize >> 10, reserved_pages << (PAGE_SHIFT - 10), + datasize >> 10, initsize >> 10); + + /* install the gate page in the global page table: */ + put_gate_page(mem_map + MAP_NR(__start_gate_section), GATE_ADDR); + +#ifndef CONFIG_IA64_SOFTSDV_HACKS + /* + * (Some) SoftSDVs seem to have a problem with this call. + * Since it's mostly a performance optimization, just don't do + * it for now... --davidm 99/12/6 + */ + efi_enter_virtual_mode(); +#endif + +#ifdef CONFIG_IA32_SUPPORT + ia32_gdt_init(); +#endif + return; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c --- v2.3.42/linux/arch/ia64/mm/tlb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/mm/tlb.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,166 @@ +/* + * TLB support routines. + * + * Copyright (C) 1998, 1999 Hewlett-Packard Co + * Copyright (C) 1998, 1999 David Mosberger-Tang + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SUPPORTED_PGBITS ( \ + 1 << _PAGE_SIZE_256M | \ + 1 << _PAGE_SIZE_64M | \ + 1 << _PAGE_SIZE_16M | \ + 1 << _PAGE_SIZE_4M | \ + 1 << _PAGE_SIZE_1M | \ + 1 << _PAGE_SIZE_256K | \ + 1 << _PAGE_SIZE_64K | \ + 1 << _PAGE_SIZE_16K | \ + 1 << _PAGE_SIZE_8K | \ + 1 << _PAGE_SIZE_4K ) + +static void wrap_context (struct mm_struct *mm); + +unsigned long ia64_next_context = (1UL << IA64_HW_CONTEXT_BITS) + 1; + + /* + * Put everything in a struct so we avoid the global offset table whenever + * possible. + */ +ia64_ptce_info_t ia64_ptce_info; + +/* + * Seralize usage of ptc.g + */ +spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED; /* see */ + +void +get_new_mmu_context (struct mm_struct *mm) +{ + if ((ia64_next_context & IA64_HW_CONTEXT_MASK) == 0) { + wrap_context(mm); + } + mm->context = ia64_next_context++; +} + +/* + * This is where we handle the case where (ia64_next_context & + * IA64_HW_CONTEXT_MASK) == 0. Whenever this happens, we need to + * flush the entire TLB and skip over region id number 0, which is + * used by the kernel. + */ +static void +wrap_context (struct mm_struct *mm) +{ + struct task_struct *task; + + /* + * We wrapped back to the first region id so we nuke the TLB + * so we can switch to the next generation of region ids. + */ + __flush_tlb_all(); + if (ia64_next_context++ == 0) { + /* + * Oops, we've used up all 64 bits of the context + * space---walk through task table to ensure we don't + * get tricked into using an old context. If this + * happens, the machine has been running for a long, + * long time! + */ + ia64_next_context = (1UL << IA64_HW_CONTEXT_BITS) + 1; + + read_lock(&tasklist_lock); + for_each_task (task) { + if (task->mm == mm) + continue; + flush_tlb_mm(mm); + } + read_unlock(&tasklist_lock); + } +} + +void +__flush_tlb_all (void) +{ + unsigned long i, j, flags, count0, count1, stride0, stride1, addr = ia64_ptce_info.base; + + count0 = ia64_ptce_info.count[0]; + count1 = ia64_ptce_info.count[1]; + stride0 = ia64_ptce_info.stride[0]; + stride1 = ia64_ptce_info.stride[1]; + + save_and_cli(flags); + for (i = 0; i < count0; ++i) { + for (j = 0; j < count1; ++j) { + asm volatile ("ptc.e %0" :: "r"(addr)); + addr += stride1; + } + addr += stride0; + } + restore_flags(flags); + ia64_insn_group_barrier(); + ia64_srlz_i(); /* srlz.i implies srlz.d */ + ia64_insn_group_barrier(); +} + +void +flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end) +{ + unsigned long size = end - start; + unsigned long nbits; + + if (mm != current->active_mm) { + /* this doesn't happen often, if at all, so it's not worth optimizing for... */ + mm->context = 0; + return; + } + + nbits = ia64_fls(size + 0xfff); + if (((1UL << nbits) & SUPPORTED_PGBITS) == 0) { + if (nbits > _PAGE_SIZE_256M) + nbits = _PAGE_SIZE_256M; + else + /* + * Some page sizes are not implemented in the + * IA-64 arch, so if we get asked to clear an + * unsupported page size, round up to the + * nearest page size. Note that we depend on + * the fact that if page size N is not + * implemented, 2*N _is_ implemented. + */ + ++nbits; + if (((1UL << nbits) & SUPPORTED_PGBITS) == 0) + panic("flush_tlb_range: BUG: nbits=%lu\n", nbits); + } + start &= ~((1UL << nbits) - 1); + + spin_lock(&ptcg_lock); + do { +#ifdef CONFIG_SMP + __asm__ __volatile__ ("ptc.g %0,%1;;srlz.i;;" + :: "r"(start), "r"(nbits<<2) : "memory"); +#else + __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); +#endif + start += (1UL << nbits); + } while (start < end); + spin_unlock(&ptcg_lock); + ia64_insn_group_barrier(); + ia64_srlz_i(); /* srlz.i implies srlz.d */ + ia64_insn_group_barrier(); +} + +void +ia64_tlb_init (void) +{ + ia64_get_ptce(&ia64_ptce_info); + __flush_tlb_all(); /* nuke left overs from bootstrapping... */ +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/sn/Makefile linux/arch/ia64/sn/Makefile --- v2.3.42/linux/arch/ia64/sn/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,25 @@ +# +# ia64/sn/Makefile +# +# Copyright (C) 1999 Silicon Graphics, Inc. +# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) +# + +CFLAGS := $(CFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSN -DSOFTSDV \ + -DLANGUAGE_C=1 -D_LANGUAGE_C=1 +AFLAGS := $(AFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSOFTSDV + +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + +all: sn.a + +O_TARGET = sn.a +O_HEADERS = +O_OBJS = sn1/sn1.a + +clean:: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/sn/sn1/Makefile linux/arch/ia64/sn/sn1/Makefile --- v2.3.42/linux/arch/ia64/sn/sn1/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/sn1/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,29 @@ +# +# ia64/platform/sn/sn1/Makefile +# +# Copyright (C) 1999 Silicon Graphics, Inc. +# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) +# + +CFLAGS := $(CFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSN -DSOFTSDV \ + -DLANGUAGE_C=1 -D_LANGUAGE_C=1 +AFLAGS := $(AFLAGS) -DCONFIG_SGI_SN1 -DSN1 -DSOFTSDV + +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -c -o $*.o $< + +all: sn1.a + +O_TARGET = sn1.a +O_HEADERS = +O_OBJS = irq.o setup.o + +ifeq ($(CONFIG_IA64_GENERIC),y) +O_OBJS += machvec.o +endif + +clean:: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.42/linux/arch/ia64/sn/sn1/irq.c linux/arch/ia64/sn/sn1/irq.c --- v2.3.42/linux/arch/ia64/sn/sn1/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/sn1/irq.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,50 @@ +#include + +#include +#include + +static int +sn1_startup_irq(unsigned int irq) +{ + return(0); +} + +static void +sn1_shutdown_irq(unsigned int irq) +{ +} + +static void +sn1_disable_irq(unsigned int irq) +{ +} + +static void +sn1_enable_irq(unsigned int irq) +{ +} + +static int +sn1_handle_irq(unsigned int irq, struct pt_regs *regs) +{ + return(0); +} + +struct hw_interrupt_type irq_type_sn1 = { + "sn1_irq", + sn1_startup_irq, + sn1_shutdown_irq, + sn1_handle_irq, + sn1_enable_irq, + sn1_disable_irq +}; + +void +sn1_irq_init (struct irq_desc desc[NR_IRQS]) +{ + int i; + + for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) { + irq_desc[i].handler = &irq_type_sn1; + } +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/sn/sn1/machvec.c linux/arch/ia64/sn/sn1/machvec.c --- v2.3.42/linux/arch/ia64/sn/sn1/machvec.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/sn1/machvec.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,4 @@ +#include +#include + +MACHVEC_DEFINE(sn1) diff -u --recursive --new-file v2.3.42/linux/arch/ia64/sn/sn1/setup.c linux/arch/ia64/sn/sn1/setup.c --- v2.3.42/linux/arch/ia64/sn/sn1/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/sn/sn1/setup.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,77 @@ +/* + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Vijay Chander(vijay@engr.sgi.com) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + * The format of "screen_info" is strange, and due to early i386-setup + * code. This is just enough to make the console code think we're on a + * VGA color display. + */ +struct screen_info sn1_screen_info = { + orig_x: 0, + orig_y: 0, + orig_video_mode: 3, + orig_video_cols: 80, + orig_video_ega_bx: 3, + orig_video_lines: 25, + orig_video_isVGA: 1, + orig_video_points: 16 +}; + +/* + * This is here so we can use the CMOS detection in ide-probe.c to + * determine what drives are present. In theory, we don't need this + * as the auto-detection could be done via ide-probe.c:do_probe() but + * in practice that would be much slower, which is painful when + * running in the simulator. Note that passing zeroes in DRIVE_INFO + * is sufficient (the IDE driver will autodetect the drive geometry). + */ +char drive_info[4*16]; + +unsigned long +sn1_map_nr (unsigned long addr) +{ + return MAP_NR_SN1(addr); +} + +void +sn1_setup(char **cmdline_p) +{ + + ROOT_DEV = to_kdev_t(0x0301); /* default to first IDE drive */ + +#if !defined (CONFIG_IA64_SOFTSDV_HACKS) + /* + * Program the timer to deliver timer ticks. 0x40 is the I/O port + * address of PIT counter 0, 0x43 is the I/O port address of the + * PIT control word. + */ + request_region(0x40,0x20,"timer"); + outb(0x34, 0x43); /* Control word */ + outb(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8, 0x40); /* MSB */ + printk("PIT: LATCH at 0x%x%x for %d HZ\n", LATCH >> 8, LATCH & 0xff, HZ); +#endif +#ifdef __SMP__ + init_smp_config(); +#endif + screen_info = sn1_screen_info; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/tools/Makefile linux/arch/ia64/tools/Makefile --- v2.3.42/linux/arch/ia64/tools/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/tools/Makefile Sun Feb 6 18:42:40 2000 @@ -0,0 +1,49 @@ +CFLAGS = -D__KERNEL__ -g -O2 -Wall -I$(TOPDIR)/include + +ifdef CONFIG_SMP + CFLAGS += -D__SMP__ +endif + +TARGET = $(TOPDIR)/include/asm-ia64/offsets.h + +all: + +clean: + rm -f print_offsets.s print_offsets offsets.h + +fastdep: offsets.h + @if ! cmp -s offsets.h ${TARGET}; then \ + echo "Updating ${TARGET}..."; \ + cp offsets.h ${TARGET}; \ + else \ + echo "${TARGET} is up to date"; \ + fi + +# +# If we're cross-compiling, we use the cross-compiler to translate +# print_offsets.c into an assembly file and then awk to translate this +# file into offsets.h. This avoids having to use a simulator to +# generate this file. This is based on an idea suggested by Asit +# Mallick. If we're running natively, we can of course just build +# print_offsets and run it. --davidm +# + +ifeq ($(CROSS_COMPILE),) + +offsets.h: print_offsets + ./print_offsets > offsets.h + +print_offsets: print_offsets.c + $(CC) $(CFLAGS) print_offsets.c -o $@ + +else + +offsets.h: print_offsets.s + $(AWK) -f print_offsets.awk $^ > $@ + +print_offsets.s: print_offsets.c + $(CC) $(CFLAGS) -S print_offsets.c -o $@ + +endif + +.PHONY: all diff -u --recursive --new-file v2.3.42/linux/arch/ia64/tools/print_offsets.awk linux/arch/ia64/tools/print_offsets.awk --- v2.3.42/linux/arch/ia64/tools/print_offsets.awk Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/tools/print_offsets.awk Sun Feb 6 18:42:40 2000 @@ -0,0 +1,70 @@ +BEGIN { + print "#ifndef _ASM_IA64_OFFSETS_H" + print "#define _ASM_IA64_OFFSETS_H" + print "/*" + print " * DO NOT MODIFY" + print " *" + print " * This file was generated by arch/ia64/tools/print_offsets.awk." + print " *" + print " */" + # + # This is a cheesy hack. Make sure that + # PF_PTRACED == 1<= 40) { + space=" " + } else { + space="" + while (len < 40) { + len += 8 + space = space"\t" + } + } + printf("#define %s%s%lu\t/* 0x%lx */\n", name, space, value, value) + } + } +} + +/tab:/ { + inside_table = 1 +} + +/tab#:/ { + inside_table = 1 +} + +END { + print "" + print "#endif /* _ASM_IA64_OFFSETS_H */" +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c --- v2.3.42/linux/arch/ia64/tools/print_offsets.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/tools/print_offsets.c Sun Feb 6 18:42:40 2000 @@ -0,0 +1,109 @@ +/* + * Utility to generate asm-ia64/offsets.h. + * + * Copyright (C) 1999-2000 Hewlett-Packard Co + * Copyright (C) 1999-2000 David Mosberger-Tang + * + * Note that this file has dual use: when building the kernel + * natively, the file is translated into a binary and executed. When + * building the kernel in a cross-development environment, this file + * gets translated into an assembly file which, in turn, is processed + * by awk to generate offsets.h. So if you make any changes to this + * file, be sure to verify that the awk procedure still works (see + * prin_offsets.awk). + */ +#include + +#include +#include +#include +#include + +#ifdef offsetof +# undef offsetof +#endif + +/* + * We _can't_ include the host's standard header file, as those are in + * potential conflict with the what the Linux kernel declares for the + * target system. + */ +extern int printf (const char *, ...); + +#define offsetof(type,field) ((char *) &((type *) 0)->field - (char *) 0) + +struct + { + const char name[256]; + unsigned long value; + } +tab[] = + { + { "IA64_TASK_SIZE", sizeof (struct task_struct) }, + { "IA64_PT_REGS_SIZE", sizeof (struct pt_regs) }, + { "IA64_SWITCH_STACK_SIZE", sizeof (struct switch_stack) }, + { "IA64_SIGINFO_SIZE", sizeof (struct siginfo) }, + { "", 0 }, /* spacer */ + { "IA64_TASK_FLAGS_OFFSET", offsetof (struct task_struct, flags) }, + { "IA64_TASK_SIGPENDING_OFFSET", offsetof (struct task_struct, sigpending) }, + { "IA64_TASK_NEED_RESCHED_OFFSET", offsetof (struct task_struct, need_resched) }, + { "IA64_TASK_THREAD_OFFSET", offsetof (struct task_struct, thread) }, + { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, + { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, + { "IA64_TASK_MM_OFFSET", offsetof (struct task_struct, mm) }, + { "IA64_PT_REGS_CR_IPSR_OFFSET", offsetof (struct pt_regs, cr_ipsr) }, + { "IA64_PT_REGS_R12_OFFSET", offsetof (struct pt_regs, r12) }, + { "IA64_PT_REGS_R8_OFFSET", offsetof (struct pt_regs, r8) }, + { "IA64_PT_REGS_R16_OFFSET", offsetof (struct pt_regs, r16) }, + { "IA64_SWITCH_STACK_B0_OFFSET", offsetof (struct switch_stack, b0) }, + { "IA64_SWITCH_STACK_CALLER_UNAT_OFFSET", offsetof (struct switch_stack, caller_unat) }, + { "IA64_SIGCONTEXT_AR_BSP_OFFSET", offsetof (struct sigcontext, sc_ar_bsp) }, + { "IA64_SIGCONTEXT_AR_RNAT_OFFSET", offsetof (struct sigcontext, sc_ar_rnat) }, + { "IA64_SIGCONTEXT_FLAGS_OFFSET", offsetof (struct sigcontext, sc_flags) }, + { "IA64_SIGCONTEXT_CFM_OFFSET", offsetof (struct sigcontext, sc_cfm) }, + { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, +}; + +static const char *tabs = "\t\t\t\t\t\t\t\t\t\t"; + +int +main (int argc, char **argv) +{ + const char *space; + int i, num_tabs; + size_t len; + + printf ("#ifndef _ASM_IA64_OFFSETS_H\n"); + printf ("#define _ASM_IA64_OFFSETS_H\n\n"); + + printf ("/*\n * DO NOT MODIFY\n *\n * This file was generated by " + "arch/ia64/tools/print_offsets.\n *\n */\n\n"); + + /* This is stretching things a bit, but entry.S needs the bit number + for PF_PTRACED and it can't include so this seems + like a reasonably solution. At least the code won't break shoudl + PF_PTRACED ever change. */ + printf ("#define PF_PTRACED_BIT\t\t\t%u\n\n", ffs (PF_PTRACED) - 1); + + for (i = 0; i < sizeof (tab) / sizeof (tab[0]); ++i) + { + if (tab[i].name[0] == '\0') + printf ("\n"); + else + { + len = strlen (tab[i].name); + + num_tabs = (40 - len) / 8; + if (num_tabs <= 0) + space = " "; + else + space = strchr(tabs, '\0') - (40 - len) / 8; + + printf ("#define %s%s%lu\t/* 0x%lx */\n", + tab[i].name, space, tab[i].value, tab[i].value); + } + } + + printf ("\n#endif /* _ASM_IA64_OFFSETS_H */\n"); + return 0; +} diff -u --recursive --new-file v2.3.42/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S --- v2.3.42/linux/arch/ia64/vmlinux.lds.S Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/vmlinux.lds.S Sun Feb 6 18:42:40 2000 @@ -0,0 +1,164 @@ +#include + +#include +#include + +OUTPUT_FORMAT("elf64-ia64-little") +OUTPUT_ARCH(ia64) +ENTRY(_start) +SECTIONS +{ + v = PAGE_OFFSET; /* this symbol is here to make debugging with kdb easier... */ + + . = KERNEL_START; + + _text = .; + _stext = .; + .text : AT(ADDR(.text) - PAGE_OFFSET) + { + *(__ivt_section) + /* these are not really text pages, but the zero page needs to be in a fixed location: */ + *(__special_page_section) + __start_gate_section = .; + *(__gate_section) + __stop_gate_section = .; + *(.text) + } + .text2 : AT(ADDR(.text2) - PAGE_OFFSET) + { *(.text2) } +#ifdef CONFIG_SMP + .text.lock : AT(ADDR(.text.lock) - PAGE_OFFSET) + { *(.text.lock) } +#endif + _etext = .; + + /* Exception table */ + . = ALIGN(16); + __start___ex_table = .; + __ex_table : AT(ADDR(__ex_table) - PAGE_OFFSET) + { *(__ex_table) } + __stop___ex_table = .; + +#if defined(CONFIG_KDB) + /* Kernel symbols and strings for kdb */ +# define KDB_MEAN_SYMBOL_SIZE 48 +# define KDB_SPACE (CONFIG_KDB_STBSIZE * KDB_MEAN_SYMBOL_SIZE) + . = ALIGN(8); + _skdb = .; + .kdb : AT(ADDR(.kdb) - PAGE_OFFSET) + { + *(kdbsymtab) + *(kdbstrings) + } + _ekdb = .; + . = _skdb + KDB_SPACE; +#endif + + /* Kernel symbol names for modules: */ + .kstrtab : AT(ADDR(.kstrtab) - PAGE_OFFSET) + { *(.kstrtab) } + + /* The initial task and kernel stack */ + . = ALIGN(PAGE_SIZE); + init_task : AT(ADDR(init_task) - PAGE_OFFSET) + { *(init_task) } + + /* Startup code */ + __init_begin = .; + .text.init : AT(ADDR(.text.init) - PAGE_OFFSET) + { *(.text.init) } + .data.init : AT(ADDR(.data.init) - PAGE_OFFSET) + { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : AT(ADDR(.setup.init) - PAGE_OFFSET) + { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : AT(ADDR(.initcall.init) - PAGE_OFFSET) + { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(PAGE_SIZE); + __init_end = .; + + .data.page_aligned : AT(ADDR(.data.page_aligned) - PAGE_OFFSET) + { *(.data.idt) } + + . = ALIGN(64); + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - PAGE_OFFSET) + { *(.data.cacheline_aligned) } + + /* Global data */ + _data = .; + + .rodata : AT(ADDR(.rodata) - PAGE_OFFSET) + { *(.rodata) } + .opd : AT(ADDR(.opd) - PAGE_OFFSET) + { *(.opd) } + .data : AT(ADDR(.data) - PAGE_OFFSET) + { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } + + __gp = ALIGN (8) + 0x200000; + + .got : AT(ADDR(.got) - PAGE_OFFSET) + { *(.got.plt) *(.got) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : AT(ADDR(.sdata) - PAGE_OFFSET) + { *(.sdata) } + _edata = .; + _bss = .; + .sbss : AT(ADDR(.sbss) - PAGE_OFFSET) + { *(.sbss) *(.scommon) } + .bss : AT(ADDR(.bss) - PAGE_OFFSET) + { *(.bss) *(COMMON) } + . = ALIGN(64 / 8); + _end = .; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + /* Discard them for now since Intel SoftSDV cannot handle them. + .comment 0 : { *(.comment) } + .note 0 : { *(.note) } + */ + /DISCARD/ : { *(.comment) } + /DISCARD/ : { *(.note) } +} diff -u --recursive --new-file v2.3.42/linux/arch/m68k/atari/joystick.c linux/arch/m68k/atari/joystick.c --- v2.3.42/linux/arch/m68k/atari/joystick.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/atari/joystick.c Wed Feb 9 11:42:35 2000 @@ -118,16 +118,11 @@ } struct file_operations atari_joystick_fops = { - NULL, /* joystick_seek */ - read_joystick, - write_joystick, - NULL, /* joystick_readdir */ - joystick_poll, - NULL, /* joystick_ioctl */ - NULL, /* joystick_mmap */ - open_joystick, - NULL, /* flush */ - release_joystick + read: read_joystick, + write: write_joystick, + poll: joystick_poll, + open: open_joystick, + release: release_joystick, }; int __init atari_joystick_init(void) diff -u --recursive --new-file v2.3.42/linux/arch/m68k/bvme6000/rtc.c linux/arch/m68k/bvme6000/rtc.c --- v2.3.42/linux/arch/m68k/bvme6000/rtc.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/bvme6000/rtc.c Wed Feb 9 11:42:35 2000 @@ -158,16 +158,9 @@ */ static struct file_operations rtc_fops = { - NULL, - NULL, - NULL, /* No write */ - NULL, /* No readdir */ - NULL, - rtc_ioctl, - NULL, /* No mmap */ - rtc_open, - NULL, /* flush */ - rtc_release + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, }; static struct miscdevice rtc_dev= diff -u --recursive --new-file v2.3.42/linux/arch/m68k/mac/adb-bus.c linux/arch/m68k/mac/adb-bus.c --- v2.3.42/linux/arch/m68k/mac/adb-bus.c Tue Aug 31 17:29:12 1999 +++ linux/arch/m68k/mac/adb-bus.c Wed Feb 9 11:42:35 2000 @@ -2498,16 +2498,11 @@ } static struct file_operations adb_fops = { - adb_lseek, - adb_read, - adb_write, - NULL, /* no readdir */ - NULL, /* no poll yet */ - NULL, /* no ioctl yet */ - NULL, /* no mmap */ - adb_open, - NULL, /* flush */ - adb_release + llseek: adb_lseek, + read: adb_read, + write: adb_write, + open: adb_open, + release: adb_release, }; int adbdev_register(int subtype, struct file_operations *fops) @@ -2683,16 +2678,11 @@ } static struct file_operations adb_fops = { - adb_lseek, - adb_read, - adb_write, - NULL, /* no readdir */ - NULL, /* no select */ - NULL, /* no ioctl */ - NULL, /* no mmap */ - adb_open, - NULL, /* flush */ - adb_release + llseek: adb_lseek, + read: adb_read, + write: adb_write, + open: adb_open, + release: adb_release, }; static struct miscdevice adb_dev = { diff -u --recursive --new-file v2.3.42/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c --- v2.3.42/linux/arch/m68k/mm/init.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/mm/init.c Wed Feb 9 20:08:09 2000 @@ -38,8 +38,6 @@ void mmu_emu_reserve_pages(unsigned long max_page); #endif -extern void show_net_buffers(void); - int do_check_pgt_cache(int low, int high) { int freed = 0; @@ -116,9 +114,6 @@ printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } extern void init_pointer_table(unsigned long ptable); diff -u --recursive --new-file v2.3.42/linux/arch/m68k/mvme16x/rtc.c linux/arch/m68k/mvme16x/rtc.c --- v2.3.42/linux/arch/m68k/mvme16x/rtc.c Fri Jan 28 15:09:07 2000 +++ linux/arch/m68k/mvme16x/rtc.c Wed Feb 9 11:42:35 2000 @@ -147,16 +147,9 @@ */ static struct file_operations rtc_fops = { - NULL, - NULL, - NULL, /* No write */ - NULL, /* No readdir */ - NULL, - rtc_ioctl, - NULL, /* No mmap */ - rtc_open, - NULL, /* flush */ - rtc_release + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, }; static struct miscdevice rtc_dev= diff -u --recursive --new-file v2.3.42/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v2.3.42/linux/arch/mips/mm/init.c Fri Oct 22 13:21:45 1999 +++ linux/arch/mips/mm/init.c Wed Feb 9 20:08:09 2000 @@ -35,8 +35,6 @@ #endif #include -extern void show_net_buffers(void); - void __bad_pte_kernel(pmd_t *pmd) { printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); @@ -266,9 +264,6 @@ printk("%ld pages in page table cache\n",pgtable_cache_size); printk("%d free pages\n", free); show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } extern unsigned long free_area_init(unsigned long, unsigned long); diff -u --recursive --new-file v2.3.42/linux/arch/ppc/Makefile linux/arch/ppc/Makefile --- v2.3.42/linux/arch/ppc/Makefile Tue Jan 11 22:31:36 2000 +++ linux/arch/ppc/Makefile Wed Feb 9 19:43:47 2000 @@ -106,19 +106,24 @@ znetboot: $(CHECKS) vmlinux ifdef CONFIG_ALL_PPC ifdef CONFIG_SMP -ifdef CONFIG_PPC64 - cp -f vmlinux /tftpboot/vmlinux.smp.64 -else cp -f vmlinux /tftpboot/vmlinux.smp -endif -else -ifdef CONFIG_PPC64 - cp -f vmlinux /tftpboot/vmlinux.64 else cp -f vmlinux /tftpboot/vmlinux endif endif + @$(MAKECOFFBOOT) $@ + @$(MAKEBOOT) $@ + @$(MAKECHRPBOOT) $@ endif + +ifdef CONFIG_PPC64 +$(BOOT_TARGETS): $(CHECKS) vmlinux + @$(MAKECOFFBOOT) $@ + @$(MAKEBOOT) $@ + @$(MAKECHRPBOOT) $@ + +znetboot: $(CHECKS) vmlinux + cp -f vmlinux /tftpboot/vmlinux.64 @$(MAKECOFFBOOT) $@ @$(MAKEBOOT) $@ @$(MAKECHRPBOOT) $@ @@ -129,31 +134,31 @@ rm -f .config arch/ppc/defconfig gemini_config: clean_config - ln -s configs/gemini_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/gemini_defconfig arch/ppc/defconfig pmac_config: clean_config - ln -s configs/pmac_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/pmac_defconfig arch/ppc/defconfig prep_config: clean_config - ln -s configs/prep_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/prep_defconfig arch/ppc/defconfig chrp_config: clean_config - ln -s configs/chrp_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/chrp_defconfig arch/ppc/defconfig common_config: clean_config - ln -s configs/common_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/common_defconfig arch/ppc/defconfig mbx_config: clean_config - ln -s configs/mbx_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/mbx_defconfig arch/ppc/defconfig apus_config: clean_config - ln -s configs/apus_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/apus_defconfig arch/ppc/defconfig oak_config: clean_config - ln -s configs/oak_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/oak_defconfig arch/ppc/defconfig walnut_config: clean_config - ln -s configs/walnut_defconfig arch/ppc/defconfig + cp -f arch/ppc/configs/walnut_defconfig arch/ppc/defconfig archclean: rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name,checks} diff -u --recursive --new-file v2.3.42/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c --- v2.3.42/linux/arch/ppc/amiga/amiints.c Sun Nov 7 16:37:34 1999 +++ linux/arch/ppc/amiga/amiints.c Wed Feb 9 19:43:47 2000 @@ -350,7 +350,8 @@ void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) { irq_node_t *node, *slow_nodes; - unsigned short flags, intena; + unsigned short intena; + unsigned long flags; kstat.irqs[0][SYS_IRQS + irq]++; if (server->count++) diff -u --recursive --new-file v2.3.42/linux/arch/ppc/amiga/cia.c linux/arch/ppc/amiga/cia.c --- v2.3.42/linux/arch/ppc/amiga/cia.c Sun Nov 7 16:37:34 1999 +++ linux/arch/ppc/amiga/cia.c Wed Feb 9 19:43:47 2000 @@ -45,10 +45,10 @@ do { \ if (irq >= IRQ_AMIGA_CIAB) { \ base = &ciab_base; \ - irq =- IRQ_AMIGA_CIAB; \ + irq -= IRQ_AMIGA_CIAB; \ } else { \ base = &ciaa_base; \ - irq =- IRQ_AMIGA_CIAA; \ + irq -= IRQ_AMIGA_CIAA; \ } \ } while (0) diff -u --recursive --new-file v2.3.42/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile --- v2.3.42/linux/arch/ppc/boot/Makefile Mon Dec 20 18:48:21 1999 +++ linux/arch/ppc/boot/Makefile Wed Feb 9 19:43:47 2000 @@ -14,7 +14,7 @@ .s.o: $(AS) -o $*.o $< .c.o: - $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $< + $(CC) $(CFLAGS) -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -D__BOOTER__ -c -o $*.o $< .S.s: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.o $< .S.o: @@ -49,7 +49,7 @@ ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000 -GZIP_FLAGS = -v9 +GZIP_FLAGS = -v9f OBJECTS := head.o misc.o ../coffboot/zlib.o CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin @@ -73,6 +73,7 @@ -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ + -D__BOOTER__ \ -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ @@ -85,6 +86,10 @@ ifdef CONFIG_PREP ./mkprep -pbp zvmlinux zImage endif +ifdef CONFIG_APUS + $(STRIP) ../../../vmlinux -o vmapus + gzip $(GZIP_FLAGS) vmapus +endif sImage: ../../../vmlinux ifdef CONFIG_GEMINI @@ -110,6 +115,7 @@ $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \ + -D__BOOTER__ \ -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ diff -u --recursive --new-file v2.3.42/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile --- v2.3.42/linux/arch/ppc/chrpboot/Makefile Mon Dec 20 18:48:21 1999 +++ linux/arch/ppc/chrpboot/Makefile Wed Feb 9 19:43:47 2000 @@ -20,7 +20,7 @@ LD_ARGS = -Ttext 0x00400000 OBJCOPY = $(CROSS_COMPILE)objcopy -OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o # initrd.o +OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o sysmap.o LIBS = $(TOPDIR)/lib/lib.a ifeq ($(CONFIG_PPC64),y) @@ -64,6 +64,9 @@ image.o: piggyback ../coffboot/vmlinux.gz ./piggyback image < ../coffboot/vmlinux.gz | $(AS) -o image.o + +sysmap.o: piggyback ../../../System.map + ./piggyback sysmap < ../../../System.map | $(AS) -o sysmap.o initrd.o: ramdisk.image.gz piggyback ./piggyback initrd < ramdisk.image.gz | $(AS) -o initrd.o diff -u --recursive --new-file v2.3.42/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c --- v2.3.42/linux/arch/ppc/chrpboot/main.c Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/chrpboot/main.c Wed Feb 9 19:43:47 2000 @@ -34,6 +34,8 @@ extern int image_len; extern char initrd_data[]; extern int initrd_len; +extern char sysmap_data[]; +extern int sysmap_len; chrpboot(int a1, int a2, void *prom) @@ -78,12 +80,12 @@ { struct bi_record *rec; - rec = (struct bi_record *)PAGE_ALIGN((unsigned long)dst+len); - + rec = (struct bi_record *)_ALIGN((unsigned long)dst+len+(1<<20)-1,(1<<20)); + rec->tag = BI_FIRST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); - + rec->tag = BI_BOOTLOADER_ID; sprintf( (char *)rec->data, "chrpboot"); rec->size = sizeof(struct bi_record) + strlen("chrpboot") + 1; @@ -95,6 +97,11 @@ rec->size = sizeof(struct bi_record) + sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); + rec->tag = BI_SYSMAP; + rec->data[0] = sysmap_data; + rec->data[1] = sysmap_len; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); rec->tag = BI_LAST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); diff -u --recursive --new-file v2.3.42/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile --- v2.3.42/linux/arch/ppc/coffboot/Makefile Tue Jan 11 22:31:36 2000 +++ linux/arch/ppc/coffboot/Makefile Wed Feb 9 19:43:47 2000 @@ -36,6 +36,9 @@ endif ifeq ($(CONFIG_PMAC),y) +chrpmain.o: chrpmain.c + $(CC) $(CFLAGS) -DSYSMAP_OFFSET=0 -DSYSMAP_SIZE=0 -c chrpmain.c + hack-coff: hack-coff.c $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c @@ -52,6 +55,12 @@ # cp vmlinux.coff /mnt # umount /mnt +miboot.image: dummy.o vmlinux.gz + $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz dummy.o $@ + +miboot.image.initrd: dummy.o vmlinux.gz + $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz miboot.image $@ + coffboot: $(COFFOBJS) no_initrd.o ld.script $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) no_initrd.o $(LIBS) @@ -82,16 +91,23 @@ vmlinux.elf: $(CHRPOBJS) no_initrd.o mknote $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS) ./mknote > note - $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment + $(OBJCOPY) $@ $@ --add-section=.note=note \ + --add-section=sysmap=../../../System.map -R .comment + $(CC) $(CFLAGS) chrpmain.c -c -o chrpmain.o \ + -DSYSMAP_OFFSET=`sh ../boot/offset $(OBJDUMP) $@ sysmap` \ + -DSYSMAP_SIZE=`sh ../boot/size $(OBJDUMP) $@ sysmap` + $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) no_initrd.o $(LIBS) + $(OBJCOPY) $@ $@ --add-section=.note=note \ + --add-section=sysmap=../../../System.map -R .comment vmlinux.elf.initrd: $(CHRPOBJS) initrd.o mknote $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) initrd.o $(LIBS) ./mknote > note $(OBJCOPY) $@ $@ --add-section=.note=note -R .comment -zImage: vmlinux.coff vmlinux.elf +zImage: vmlinux.coff vmlinux.elf miboot.image -zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd +zImage.initrd: vmlinux.coff.initrd vmlinux.elf.initrd miboot.image.initrd else znetboot: vmlinux.gz @@ -118,5 +134,7 @@ clean: rm -f hack-coff coffboot zImage vmlinux.coff vmlinux.gz + rm -f mknote piggyback vmlinux.elf note + rm -f miboot.image miboot.image.initrd fastdep: diff -u --recursive --new-file v2.3.42/linux/arch/ppc/coffboot/chrpmain.c linux/arch/ppc/coffboot/chrpmain.c --- v2.3.42/linux/arch/ppc/coffboot/chrpmain.c Tue Jan 11 22:31:36 2000 +++ linux/arch/ppc/coffboot/chrpmain.c Wed Feb 9 19:43:47 2000 @@ -92,8 +92,7 @@ void make_bi_recs(unsigned long addr) { struct bi_record *rec; - - rec = (struct bi_record *)PAGE_ALIGN(addr); + rec = (struct bi_record *)_ALIGN((unsigned long)addr+(1<<20)-1,(1<<20)); rec->tag = BI_FIRST; rec->size = sizeof(struct bi_record); @@ -109,7 +108,15 @@ rec->data[1] = 1; rec->size = sizeof(struct bi_record) + sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); - + +#ifdef SYSMAP_OFFSET + rec->tag = BI_SYSMAP; + rec->data[0] = SYSMAP_OFFSET; + rec->data[1] = SYSMAP_SIZE; + rec->size = sizeof(struct bi_record) + sizeof(unsigned long); + rec = (struct bi_record *)((unsigned long)rec + rec->size); +#endif /* SYSMAP_OFFSET */ + rec->tag = BI_LAST; rec->size = sizeof(struct bi_record); rec = (struct bi_record *)((unsigned long)rec + rec->size); diff -u --recursive --new-file v2.3.42/linux/arch/ppc/coffboot/dummy.c linux/arch/ppc/coffboot/dummy.c --- v2.3.42/linux/arch/ppc/coffboot/dummy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/coffboot/dummy.c Wed Feb 9 19:43:47 2000 @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff -u --recursive --new-file v2.3.42/linux/arch/ppc/coffboot/main.c linux/arch/ppc/coffboot/main.c --- v2.3.42/linux/arch/ppc/coffboot/main.c Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/coffboot/main.c Wed Feb 9 19:43:47 2000 @@ -112,8 +112,8 @@ #endif { struct bi_record *rec; - - rec = (struct bi_record *)PAGE_ALIGN((unsigned long)dst+len); + + rec = (struct bi_record *)_ALIGN((unsigned long)dst+len+(1<<20)-1,(1<<20)); rec->tag = BI_FIRST; rec->size = sizeof(struct bi_record); diff -u --recursive --new-file v2.3.42/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.3.42/linux/arch/ppc/config.in Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/config.in Wed Feb 9 19:43:47 2000 @@ -15,7 +15,7 @@ comment 'Platform support' define_bool CONFIG_PPC y choice 'Processor Type' \ - "6xx/7xx CONFIG_6xx \ + "6xx/7xx/7400 CONFIG_6xx \ 4xx CONFIG_4xx \ 630/Power3(64-Bit) CONFIG_PPC64 \ 82xx CONFIG_82xx \ @@ -97,6 +97,9 @@ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_APUS" != "y" ]; then define_bool CONFIG_PCI y fi +if [ "$CONFIG_PREP" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" -o "$CONFIG_ALL_PPC" = "y"]; then + define_bool CONFIG_PCI y +fi bool 'Networking support' CONFIG_NET bool 'Sysctl support' CONFIG_SYSCTL @@ -140,6 +143,7 @@ bool ' Include MacIO ADB driver' CONFIG_ADB_MACIO bool ' Include PMU (Powerbook) ADB driver' CONFIG_ADB_PMU bool 'Support for ADB keyboard' CONFIG_ADB_KEYBOARD + bool 'Support for ADB mouse' CONFIG_ADBMOUSE fi bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP diff -u --recursive --new-file v2.3.42/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.3.42/linux/arch/ppc/configs/common_defconfig Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/configs/common_defconfig Wed Feb 9 19:43:47 2000 @@ -1,6 +1,7 @@ # # Automatically generated make config: don't edit # +# CONFIG_UID16 is not set # # Code maturity level options @@ -37,6 +38,7 @@ # # CONFIG_PCI is not set CONFIG_PCI=y +CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y @@ -45,6 +47,7 @@ CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set # CONFIG_PARPORT is not set CONFIG_VGA_CONSOLE=y @@ -58,6 +61,7 @@ CONFIG_ADB_MACIO=y CONFIG_ADB_PMU=y CONFIG_ADB_KEYBOARD=y +CONFIG_ADBMOUSE=y CONFIG_PROC_DEVICETREE=y # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y @@ -84,7 +88,7 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set CONFIG_BLK_DEV_IDEFLOPPY=y -# CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDESCSI=y # # IDE chipset support/bugfixes @@ -111,7 +115,6 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_XD is not set # CONFIG_BLK_DEV_DAC960 is not set -CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set CONFIG_BLK_DEV_IDE_MODES=y # CONFIG_BLK_DEV_HD is not set @@ -178,11 +181,12 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set +CONFIG_CHR_DEV_SG=y # # 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 @@ -244,6 +248,12 @@ CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=5 CONFIG_SCSI_MAC53C94=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set # # Network device support @@ -266,6 +276,7 @@ CONFIG_MACE=y CONFIG_BMAC=y # CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set @@ -407,17 +418,27 @@ CONFIG_UNIX98_PTY_COUNT=256 # +# I2C support +# +# CONFIG_I2C is not set + +# # Mice # CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -# CONFIG_ADBMOUSE is not set +CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set # @@ -431,11 +452,6 @@ # Video For Linux # # CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -445,9 +461,10 @@ # # CONFIG_FTAPE is not set # CONFIG_DRM is not set +# CONFIG_AGP is not set # -# Support for USB +# USB support # CONFIG_USB=y @@ -456,31 +473,40 @@ # # CONFIG_USB_UHCI is not set CONFIG_USB_OHCI=y -CONFIG_USB_OHCI_DEBUG=y -# CONFIG_USB_OHCI_HCD is not set # # Miscellaneous USB options # -CONFIG_USB_DEBUG_ISOC=y -CONFIG_USB_PROC=y -# CONFIG_USB_EZUSB is not set +# CONFIG_USB_DEVICEFS is not set # # USB Devices # -CONFIG_USB_HUB=y -CONFIG_USB_MOUSE=y -CONFIG_USB_HP_SCANNER=m -CONFIG_USB_KBD=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_SCANNER is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set # CONFIG_USB_SERIAL is not set # CONFIG_USB_CPIA is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set CONFIG_USB_SCSI=m CONFIG_USB_SCSI_DEBUG=y +# CONFIG_USB_DABUSB is not set + +# +# USB HID +# +# CONFIG_USB_HID is not set +CONFIG_USB_KBD=y +CONFIG_USB_MOUSE=y +# CONFIG_USB_GRAPHIRE is not set +# CONFIG_USB_WMFORCE is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set # # Filesystems @@ -493,9 +519,9 @@ # CONFIG_BFS_FS is not set # CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set -# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -505,6 +531,7 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -513,7 +540,7 @@ # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y CONFIG_NFSD=y -# CONFIG_NFSD_SUN is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -525,8 +552,6 @@ # CONFIG_PARTITION_ADVANCED is not set CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # @@ -540,6 +565,7 @@ # CONFIG_SOUND_ESSSOLO1 is not set # CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=y diff -u --recursive --new-file v2.3.42/linux/arch/ppc/configs/gemini_defconfig linux/arch/ppc/configs/gemini_defconfig --- v2.3.42/linux/arch/ppc/configs/gemini_defconfig Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/configs/gemini_defconfig Wed Feb 9 19:43:47 2000 @@ -1,6 +1,7 @@ # # Automatically generated make config: don't edit # +# CONFIG_UID16 is not set # # Code maturity level options @@ -217,6 +218,11 @@ # CONFIG_SCSI_MAC53C94 is not set # +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# # Network device support # CONFIG_NETDEVICES=y @@ -237,6 +243,7 @@ # CONFIG_MACE is not set # CONFIG_BMAC is not set CONFIG_NCR885E=y +# CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set @@ -414,4 +421,4 @@ # # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set -CONFIG_XMON=y +# CONFIG_XMON is not set diff -u --recursive --new-file v2.3.42/linux/arch/ppc/configs/oak_defconfig linux/arch/ppc/configs/oak_defconfig --- v2.3.42/linux/arch/ppc/configs/oak_defconfig Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/configs/oak_defconfig Wed Feb 9 19:43:47 2000 @@ -18,7 +18,6 @@ # CONFIG_8xx is not set CONFIG_OAK=y # CONFIG_WALNUT is not set -# CONFIG_PCI is not set # CONFIG_SMP is not set CONFIG_MACH_SPECIFIC=y # CONFIG_MATH_EMULATION is not set @@ -33,6 +32,7 @@ # # General setup # +# CONFIG_PCI is not set CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y @@ -233,6 +233,11 @@ # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set # # Mice diff -u --recursive --new-file v2.3.42/linux/arch/ppc/configs/walnut_defconfig linux/arch/ppc/configs/walnut_defconfig --- v2.3.42/linux/arch/ppc/configs/walnut_defconfig Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/configs/walnut_defconfig Wed Feb 9 19:43:47 2000 @@ -18,7 +18,6 @@ # CONFIG_8xx is not set # CONFIG_OAK is not set CONFIG_WALNUT=y -CONFIG_PCI=y # CONFIG_SMP is not set CONFIG_MACH_SPECIFIC=y # CONFIG_MATH_EMULATION is not set @@ -33,6 +32,7 @@ # # General setup # +CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y @@ -235,6 +235,11 @@ # CONFIG_UNIX98_PTYS is not set # +# I2C support +# +CONFIG_I2C=y + +# # Mice # # CONFIG_BUSMOUSE is not set @@ -315,8 +320,8 @@ # Partition Types # # CONFIG_PARTITION_ADVANCED is not set -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set diff -u --recursive --new-file v2.3.42/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.3.42/linux/arch/ppc/defconfig Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/defconfig Wed Feb 9 19:43:47 2000 @@ -1,6 +1,7 @@ # # Automatically generated make config: don't edit # +# CONFIG_UID16 is not set # # Code maturity level options @@ -37,6 +38,7 @@ # # CONFIG_PCI is not set CONFIG_PCI=y +CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y @@ -45,6 +47,7 @@ CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set # CONFIG_PARPORT is not set CONFIG_VGA_CONSOLE=y @@ -58,6 +61,7 @@ CONFIG_ADB_MACIO=y CONFIG_ADB_PMU=y CONFIG_ADB_KEYBOARD=y +CONFIG_ADBMOUSE=y CONFIG_PROC_DEVICETREE=y # CONFIG_TOTALMP is not set CONFIG_BOOTX_TEXT=y @@ -84,7 +88,7 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set CONFIG_BLK_DEV_IDEFLOPPY=y -# CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDESCSI=y # # IDE chipset support/bugfixes @@ -111,7 +115,6 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_XD is not set # CONFIG_BLK_DEV_DAC960 is not set -CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set CONFIG_BLK_DEV_IDE_MODES=y # CONFIG_BLK_DEV_HD is not set @@ -178,11 +181,12 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y -# CONFIG_CHR_DEV_SG is not set +CONFIG_CHR_DEV_SG=y # # 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 @@ -244,6 +248,12 @@ CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=5 CONFIG_SCSI_MAC53C94=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set # # Network device support @@ -266,6 +276,7 @@ CONFIG_MACE=y CONFIG_BMAC=y # CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set @@ -407,17 +418,27 @@ CONFIG_UNIX98_PTY_COUNT=256 # +# I2C support +# +# CONFIG_I2C is not set + +# # Mice # CONFIG_BUSMOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -# CONFIG_ADBMOUSE is not set +CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set # @@ -431,11 +452,6 @@ # Video For Linux # # CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -445,9 +461,10 @@ # # CONFIG_FTAPE is not set # CONFIG_DRM is not set +# CONFIG_AGP is not set # -# Support for USB +# USB support # CONFIG_USB=y @@ -456,31 +473,40 @@ # # CONFIG_USB_UHCI is not set CONFIG_USB_OHCI=y -CONFIG_USB_OHCI_DEBUG=y -# CONFIG_USB_OHCI_HCD is not set # # Miscellaneous USB options # -CONFIG_USB_DEBUG_ISOC=y -CONFIG_USB_PROC=y -# CONFIG_USB_EZUSB is not set +# CONFIG_USB_DEVICEFS is not set # # USB Devices # -CONFIG_USB_HUB=y -CONFIG_USB_MOUSE=y -CONFIG_USB_HP_SCANNER=m -CONFIG_USB_KBD=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_SCANNER is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set # CONFIG_USB_SERIAL is not set # CONFIG_USB_CPIA is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set # CONFIG_USB_DC2XX is not set CONFIG_USB_SCSI=m CONFIG_USB_SCSI_DEBUG=y +# CONFIG_USB_DABUSB is not set + +# +# USB HID +# +# CONFIG_USB_HID is not set +CONFIG_USB_KBD=y +CONFIG_USB_MOUSE=y +# CONFIG_USB_GRAPHIRE is not set +# CONFIG_USB_WMFORCE is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set # # Filesystems @@ -493,9 +519,9 @@ # CONFIG_BFS_FS is not set # CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set -# CONFIG_UDF_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set @@ -505,6 +531,7 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set # @@ -513,7 +540,7 @@ # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y CONFIG_NFSD=y -# CONFIG_NFSD_SUN is not set +# CONFIG_NFSD_V3 is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -525,8 +552,6 @@ # CONFIG_PARTITION_ADVANCED is not set CONFIG_MAC_PARTITION=y CONFIG_MSDOS_PARTITION=y -# CONFIG_SGI_PARTITION is not set -# CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # @@ -540,6 +565,7 @@ # CONFIG_SOUND_ESSSOLO1 is not set # CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set CONFIG_SOUND_OSS=y diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.3.42/linux/arch/ppc/kernel/Makefile Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/Makefile Wed Feb 9 19:43:47 2000 @@ -38,7 +38,7 @@ endif ifdef CONFIG_PCI -O_OBJS += pci.o +O_OBJS += pci.o pci-dma.o endif ifdef CONFIG_KGDB @@ -59,8 +59,16 @@ ifeq ($(CONFIG_4xx),y) O_OBJS += ppc4xx_pic.o - ifeq ($(CONFIG_OAK),y) - O_OBJS += oak_setup.o +endif + +ifeq ($(CONFIG_OAK),y) + O_OBJS += oak_setup.o +endif + +ifeq ($(CONFIG_WALNUT),y) + O_OBJS += walnut_setup.o + ifeq ($(CONFIG_PCI),y) + O_OBJS += galaxy_pci.o endif endif @@ -81,6 +89,9 @@ O_OBJS += pmac_nvram.o endif ifeq ($(CONFIG_6xx),y) + O_OBJS += open_pic.o indirect_pci.o +endif +ifeq ($(CONFIG_PPC64),y) O_OBJS += open_pic.o indirect_pci.o endif ifeq ($(CONFIG_APUS),y) diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.3.42/linux/arch/ppc/kernel/apus_setup.c Sun Nov 7 16:37:34 1999 +++ linux/arch/ppc/kernel/apus_setup.c Wed Feb 9 19:43:47 2000 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -28,8 +27,41 @@ #include #endif -/* Get the IDE stuff from the 68k file */ #include +#define T_CHAR (0x0000) /* char: don't touch */ +#define T_SHORT (0x4000) /* short: 12 -> 21 */ +#define T_INT (0x8000) /* int: 1234 -> 4321 */ +#define T_TEXT (0xc000) /* text: 12 -> 21 */ + +#define T_MASK_TYPE (0xc000) +#define T_MASK_COUNT (0x3fff) + +#define D_CHAR(cnt) (T_CHAR | (cnt)) +#define D_SHORT(cnt) (T_SHORT | (cnt)) +#define D_INT(cnt) (T_INT | (cnt)) +#define D_TEXT(cnt) (T_TEXT | (cnt)) + +static u_short driveid_types[] = { + D_SHORT(10), /* config - vendor2 */ + D_TEXT(20), /* serial_no */ + D_SHORT(3), /* buf_type, buf_size - ecc_bytes */ + D_TEXT(48), /* fw_rev - model */ + D_CHAR(2), /* max_multsect - vendor3 */ + D_SHORT(1), /* dword_io */ + D_CHAR(2), /* vendor4 - capability */ + D_SHORT(1), /* reserved50 */ + D_CHAR(4), /* vendor5 - tDMA */ + D_SHORT(4), /* field_valid - cur_sectors */ + D_INT(1), /* cur_capacity */ + D_CHAR(2), /* multsect - multsect_valid */ + D_INT(1), /* lba_capacity */ + D_SHORT(194) /* dma_1word - reservedyy */ +}; + +#define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types)) + +#if 0 /* Get rid of this crud */ +/* Get the IDE stuff from the 68k file */ #define ide_init_hwif_ports m68k_ide_init_hwif_ports #define ide_default_irq m68k_ide_default_irq #undef ide_request_irq @@ -57,6 +89,7 @@ #undef ide_release_region #undef ide_fix_driveid /*-------------------------------------------*/ +#endif #include #include @@ -411,33 +444,6 @@ { } -#if defined(CONFIG_WHIPPET_SERIAL)||defined(CONFIG_MULTIFACE_III_TTY)||defined(CONFIG_GVPIOEXT)||defined(CONFIG_AMIGA_BUILTIN_SERIAL) - -long m68k_rs_init(void); -int m68k_register_serial(struct serial_struct *); -void m68k_unregister_serial(int); -long m68k_serial_console_init(long, long ); - -int rs_init(void) -{ - return m68k_rs_init(); -} -int register_serial(struct serial_struct *p) -{ - return m68k_register_serial(p); -} -void unregister_serial(int i) -{ - m68k_unregister_serial(i); -} -#ifdef CONFIG_SERIAL_CONSOLE -long serial_console_init(long kmem_start, long kmem_end) -{ - return m68k_serial_console_init(kmem_start, kmem_end); -} -#endif -#endif - /*********************************************************** FLOPPY */ #if defined(CONFIG_AMIGA_FLOPPY) __init @@ -673,7 +679,7 @@ int apus_ide_default_irq(ide_ioreg_t base) { - return m68k_ide_default_irq(base); + return 0; } ide_ioreg_t @@ -685,7 +691,7 @@ int apus_ide_check_region(ide_ioreg_t from, unsigned int extent) { - return m68k_ide_check_region(from, extent); + return 0; } void @@ -693,27 +699,66 @@ unsigned int extent, const char *name) { - m68k_ide_request_region(from, extent, name); } void apus_ide_release_region(ide_ioreg_t from, unsigned int extent) { - m68k_ide_release_region(from, extent); } void apus_ide_fix_driveid(struct hd_driveid *id) { - m68k_ide_fix_driveid(id); + u_char *p = (u_char *)id; + int i, j, cnt; + u_char t; + + if (!MACH_IS_AMIGA && !MACH_IS_MAC) + return; + for (i = 0; i < num_driveid_types; i++) { + cnt = driveid_types[i] & T_MASK_COUNT; + switch (driveid_types[i] & T_MASK_TYPE) { + case T_CHAR: + p += cnt; + break; + case T_SHORT: + for (j = 0; j < cnt; j++) { + t = p[0]; + p[0] = p[1]; + p[1] = t; + p += 2; + } + break; + case T_INT: + for (j = 0; j < cnt; j++) { + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = t; + p += 4; + } + break; + case T_TEXT: + for (j = 0; j < cnt; j += 2) { + t = p[0]; + p[0] = p[1]; + p[1] = t; + p += 2; + } + break; + } + } } __init void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { - m68k_ide_init_hwif_ports(hw, data_port, ctrl_port, irq); + if (data_port || ctrl_port) + printk("apus_ide_init_hwif_ports: must not be called\n"); } #endif /****************************************************** IRQ stuff */ @@ -732,7 +777,7 @@ /* IPL must be between 0 and 7 */ __apus -static inline void apus_set_IPL(int ipl) +static inline void apus_set_IPL(unsigned long ipl) { APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); @@ -743,42 +788,22 @@ __apus static inline unsigned long apus_get_IPL(void) { - unsigned short __f; + /* This returns the present IPL emulation level. */ + unsigned long __f; APUS_READ(APUS_IPL_EMU, __f); return ((~__f) & IPLEMU_IPLMASK); } __apus -static inline unsigned long apus_get_prev_IPL(void) -{ - unsigned short __f; - APUS_READ(APUS_IPL_EMU, __f); - return ((~__f >> 3) & IPLEMU_IPLMASK); -} - - -__apus -static void apus_save_flags(unsigned long* flags) +static inline unsigned long apus_get_prev_IPL(struct pt_regs* regs) { - *flags = apus_get_IPL(); -} - -__apus -static void apus_restore_flags(unsigned long flags) -{ - apus_set_IPL(flags); -} - -__apus -static void apus_sti(void) -{ - apus_set_IPL(0); -} - -__apus -static void apus_cli(void) -{ - apus_set_IPL(7); + /* The value saved in mq is the IPL_EMU value at the time of + interrupt. The lower bits are the current interrupt level, + the upper bits the requested level. Thus, to restore the + IPL level to the post-interrupt state, we will need to use + the lower bits. */ + unsigned long __f = regs->mq; + return ((~__f) & IPLEMU_IPLMASK); } @@ -802,6 +827,22 @@ return amiga_request_irq (irq, handler, irqflags, devname, dev_id); } + +/* In Linux/m68k the sys_request_irq deals with vectors 0-7. That's what + callers expect - but on Linux/APUS we actually use the IRQ_AMIGA_AUTO + vectors (24-31), so we put this dummy function in between to adjust + the vector argument (rather have cruft here than in the generic irq.c). */ +int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, const char * devname, void *dev_id) +{ + extern int request_sysirq(unsigned int irq, + void (*handler)(int, void *, + struct pt_regs *), + unsigned long irqflags, + const char * devname, void *dev_id); + return request_sysirq(irq+IRQ_AMIGA_AUTO, handler, irqflags, + devname, dev_id); +} #endif __apus @@ -809,14 +850,17 @@ { #ifdef CONFIG_APUS int level = apus_get_IPL(); - unsigned short ints = custom.intreqr & custom.intenar; + +#ifdef __INTERRUPT_DEBUG + printk("<%d:%d>", level, apus_get_prev_IPL(regs)); +#endif if (0 == level) - return -1; + return -8; if (7 == level) - return -2; + return -9; - return level; + return level + IRQ_AMIGA_AUTO; #else return 0; #endif @@ -824,10 +868,13 @@ __apus -void apus_post_irq(int level) +void apus_post_irq(struct pt_regs* regs, int level) { +#ifdef __INTERRUPT_DEBUG + printk("{%d}", apus_get_prev_IPL(regs)); +#endif /* Restore IPL to the previous value */ - apus_set_IPL(apus_get_IPL()); + apus_set_IPL(apus_get_prev_IPL(regs)); } @@ -903,11 +950,28 @@ return NULL; } +extern void amiga_enable_irq(unsigned int irq); +extern void amiga_disable_irq(unsigned int irq); + +struct hw_interrupt_type amiga_irqctrl = { + " Amiga ", + NULL, + NULL, + amiga_enable_irq, + amiga_disable_irq, + 0, + 0 +}; + + __init void apus_init_IRQ(void) { int i; + for ( i = 0 ; i < NR_IRQS ; i++ ) + irq_desc[i].ctl = &amiga_irqctrl; + for (i = 0; i < NUM_IRQ_NODES; i++) nodes[i].handler = NULL; @@ -919,10 +983,10 @@ amiga_init_IRQ(); - int_control.int_sti = apus_sti; - int_control.int_cli = apus_cli; - int_control.int_save_flags = apus_save_flags; - int_control.int_restore_flags = apus_restore_flags; + int_control.int_sti = __no_use_sti; + int_control.int_cli = __no_use_cli; + int_control.int_save_flags = __no_use_save_flags; + int_control.int_restore_flags = __no_use_restore_flags; } __init diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.3.42/linux/arch/ppc/kernel/chrp_pci.c Thu Jan 6 12:57:47 2000 +++ linux/arch/ppc/kernel/chrp_pci.c Wed Feb 9 19:43:47 2000 @@ -273,14 +273,13 @@ chrp_pcibios_fixup(void) { struct pci_dev *dev; - - /* some of IBM chrps have > 1 bus */ - if ( !strncmp("IBM", get_property(find_path_device("/"), - "name", NULL),3) ) - { - - } - + int i; + extern struct pci_ops generic_pci_ops; + + /* Some IBM's with the python have >1 bus, this finds them */ + for ( i = 0; i < python_busnr ; i++ ) + pci_scan_bus(i+1, &generic_pci_ops, NULL); + /* PCI interrupts are controlled by the OpenPIC */ pci_for_each_dev(dev) { if ( dev->irq ) diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.3.42/linux/arch/ppc/kernel/chrp_setup.c Wed Dec 29 13:13:12 1999 +++ linux/arch/ppc/kernel/chrp_setup.c Wed Feb 9 19:43:47 2000 @@ -249,7 +249,6 @@ else #endif ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ -sprintf(cmd_line, "console=ttyS0,9600 console=tty0"); printk("Boot arguments: %s\n", cmd_line); request_region(0x20,0x20,"pic1"); @@ -384,7 +383,7 @@ return irq; } -void chrp_post_irq(int irq) +void chrp_post_irq(struct pt_regs* regs, int irq) { /* * If it's an i8259 irq then we've already done the @@ -394,7 +393,7 @@ * We do it this way since our irq_desc[irq].handler can change * with RTL and no longer be open_pic -- Cort */ - if ( irq >= open_pic.irq_offset) + if ( irq >= open_pic_irq_offset) openpic_eoi( smp_processor_id() ); } @@ -411,10 +410,11 @@ (*(unsigned long *)get_property(np, "8259-interrupt-acknowledge", NULL)); } - open_pic.irq_offset = 16; + open_pic_irq_offset = 16; for ( i = 16 ; i < NR_IRQS ; i++ ) irq_desc[i].handler = &open_pic; openpic_init(1); + enable_irq(IRQ_8259_CASCADE); for ( i = 0 ; i < 16 ; i++ ) irq_desc[i].handler = &i8259_pic; i8259_init(); diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/chrp_time.c linux/arch/ppc/kernel/chrp_time.c --- v2.3.42/linux/arch/ppc/kernel/chrp_time.c Tue Aug 31 17:29:12 1999 +++ linux/arch/ppc/kernel/chrp_time.c Wed Feb 9 19:43:47 2000 @@ -171,9 +171,10 @@ if (fp != 0) freq = *fp; } - freq *= 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%d\n", freq, divisor); + freq *= 30; + divisor = 30; + printk("time_init: decrementer frequency = %lu/%d (%d MHz)\n", freq, + divisor, (freq/divisor)>>20); decrementer_count = freq / HZ / divisor; count_period_num = divisor; count_period_den = freq / 1000000; diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S --- v2.3.42/linux/arch/ppc/kernel/entry.S Fri Jan 28 15:09:07 2000 +++ linux/arch/ppc/kernel/entry.S Wed Feb 9 19:43:47 2000 @@ -256,6 +256,15 @@ 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 */ + mtmsr r0 /* Update machine state */ + lwz r0,_MSR(r1) mtspr SRR0,r2 mtspr SRR1,r0 @@ -271,7 +280,7 @@ bl schedule_tail b ret_from_except #endif - + .globl ret_from_intercept ret_from_intercept: /* @@ -291,7 +300,7 @@ .globl ret_from_except ret_from_except: -0: /* disable interrupts */ +0: /* disable interrupts */ lis r30,int_control@h ori r30,r30,int_control@l lwz r30,0(r30) @@ -342,16 +351,26 @@ .globl do_signal_ret do_signal_ret: b 0b -8: addi r4,r1,INT_FRAME_SIZE /* size of frame */ +8: /* + * We need to hard disable here even if RTL is active since + * being interrupted after here trashes the SPRG2 + * -- Cort + */ + mfmsr r0 /* Get current interrupt state */ + rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ + mtmsr r0 /* Update machine state */ + + addi r4,r1,INT_FRAME_SIZE /* size of frame */ stw r4,THREAD+KSP(r2) /* save kernel stack pointer */ tophys(r3,r1) mtspr SPRG2,r3 /* phys exception stack pointer */ + b 11f 10: /* make sure we hard disable here, even if rtl is active -- 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 */ - +11: lwz r2,_CTR(r1) lwz r0,_LINK(r1) mtctr r2 diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c --- v2.3.42/linux/arch/ppc/kernel/feature.c Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/feature.c Thu Feb 10 12:37:22 2000 @@ -8,85 +8,144 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * + * BenH: Changed implementation to work on multiple registers + * polarity is also taken into account. Removed delay (now + * responsibility of the caller). Added spinlocks. + * */ +#include #include #include #include #include #include +#include #include #include +#include #include #include #include -#define MAX_FEATURE_REGS 2 #undef DEBUG_FEATURE -static u32 feature_bits_pbook[] = { - 0, /* FEATURE_null */ - OH_SCC_RESET, /* FEATURE_Serial_reset */ - OH_SCC_ENABLE, /* FEATURE_Serial_enable */ - OH_SCCA_IO, /* FEATURE_Serial_IO_A */ - OH_SCCB_IO, /* FEATURE_Serial_IO_B */ - OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */ - OH_MESH_ENABLE, /* FEATURE_MESH_enable */ - OH_IDE_ENABLE, /* FEATURE_IDE_enable */ - OH_VIA_ENABLE, /* FEATURE_VIA_enable */ - OH_IDECD_POWER, /* FEATURE_CD_power */ - OH_BAY_RESET, /* FEATURE_Mediabay_reset */ - OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */ - OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */ - OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */ - OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ - 0, /* FEATURE_BMac_reset */ - 0, /* FEATURE_BMac_IO_enable */ - 0, /* FEATURE_Modem_Reset -> guess... */ - OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */ - OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */ +#define MAX_FEATURE_CONTROLLERS 2 +#define MAX_FEATURE_OFFSET 0x50 +#define FREG(c,r) (&(((c)->reg)[(r)>>2])) + +typedef struct feature_bit { + int reg; /* reg. offset from mac-io base */ + unsigned int polarity; /* 0 = normal, 1 = inverse */ + unsigned int mask; /* bit mask */ +} fbit; + +/* I don't have an OHare machine to test with, so I left those as they + * were. Someone with such a machine chould check out what OF says and + * try too see if they match the heathrow ones and should be changed too + */ +static fbit feature_bits_ohare_pbook[] = { + {0x38,0,0}, /* FEATURE_null */ + {0x38,0,OH_SCC_RESET}, /* FEATURE_Serial_reset */ + {0x38,0,OH_SCC_ENABLE}, /* FEATURE_Serial_enable */ + {0x38,0,OH_SCCA_IO}, /* FEATURE_Serial_IO_A */ + {0x38,0,OH_SCCB_IO}, /* FEATURE_Serial_IO_B */ + {0x38,0,OH_FLOPPY_ENABLE}, /* FEATURE_SWIM3_enable */ + {0x38,0,OH_MESH_ENABLE}, /* FEATURE_MESH_enable */ + {0x38,0,OH_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ + {0x38,1,OH_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ + {0x38,0,OH_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ + {0x38,1,OH_BAY_RESET_N}, /* FEATURE_Mediabay_reset */ + {0x38,1,OH_BAY_POWER_N}, /* FEATURE_Mediabay_power */ + {0x38,0,OH_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */ + {0x38,0,OH_BAY_IDE_ENABLE}, /* FEATURE_Mediabay_IDE_enable */ + {0x38,1,OH_IDE1_RESET_N}, /* FEATURE_Mediabay_IDE_reset */ + {0x38,0,OH_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */ + {0x38,0,0}, /* FEATURE_BMac_reset */ + {0x38,0,0}, /* FEATURE_BMac_IO_enable */ + {0x38,0,0}, /* FEATURE_Modem_power */ + {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ + {0x38,0,0}, /* FEATURE_Sound_Power */ + {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ + {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x38,0,0}, /* FEATURE_IDE2_reset */ }; -/* assume these are the same as the ohare until proven otherwise */ -static u32 feature_bits_heathrow[] = { - 0, /* FEATURE_null */ - OH_SCC_RESET, /* FEATURE_Serial_reset */ - OH_SCC_ENABLE, /* FEATURE_Serial_enable */ - OH_SCCA_IO, /* FEATURE_Serial_IO_A */ - OH_SCCB_IO, /* FEATURE_Serial_IO_B */ - OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */ - OH_MESH_ENABLE, /* FEATURE_MESH_enable */ - OH_IDE_ENABLE, /* FEATURE_IDE_enable */ - OH_VIA_ENABLE, /* FEATURE_VIA_enable */ - OH_IDECD_POWER, /* FEATURE_CD_power */ - OH_BAY_RESET, /* FEATURE_Mediabay_reset */ - OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */ - OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */ - OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */ - OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ - 0x80000000, /* FEATURE_BMac_reset */ - 0x60000000, /* FEATURE_BMac_IO_enable */ - 0x02000000, /* FEATURE_Modem_Reset -> guess...*/ - OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */ - OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */ +/* Those bits are from a PowerBook. It's possible that desktop machines + * based on heathrow need a different definition or some bits removed + */ +static fbit feature_bits_heathrow[] = { + {0x38,0,0}, /* FEATURE_null */ + {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */ + {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ + {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ + {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */ + {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ + {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ + {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ + {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ + {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ + {0x38,1,HRW_BAY_RESET_N}, /* FEATURE_Mediabay_reset */ + {0x38,1,HRW_BAY_POWER_N}, /* FEATURE_Mediabay_power */ + {0x38,0,HRW_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */ + {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_Mediabay_IDE_enable */ + {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_Mediabay_IDE_reset */ + {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */ + {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ + {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ + {0x38,1,HRW_MODEM_POWER_N}, /* FEATURE_Modem_power */ + {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ + {0x38,1,HRW_SOUND_POWER_N}, /* FEATURE_Sound_Power */ + {0x38,0,HRW_SOUND_CLK_ENABLE}, /* FEATURE_Sound_CLK_Enable */ + {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x38,0,0}, /* FEATURE_IDE2_reset */ +}; + +/* Those bits are from an iBook. + */ +static fbit feature_bits_keylargo[] = { + {0x38,0,0}, /* FEATURE_null */ + {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,0x00000054}, /* FEATURE_Serial_enable */ + {0x38,0,0}, /* FEATURE_Serial_IO_A */ + {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,0}, /* FEATURE_SWIM3_enable */ + {0x38,0,0}, /* FEATURE_MESH_enable */ + {0x38,0,0}, /* FEATURE_IDE0_enable */ + {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */ + {0x38,0,0}, /* FEATURE_IOBUS_enable */ + {0x38,0,0}, /* FEATURE_Mediabay_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_power */ + {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ + {0x38,0,0}, /* FEATURE_Mediabay_IDE_enable */ + {0x3c,1,0x08000000}, /* FEATURE_Mediabay_IDE_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ + {0x38,0,0}, /* FEATURE_BMac_reset */ + {0x38,0,0}, /* FEATURE_BMac_IO_enable */ + {0x40,1,0x02000000}, /* FEATURE_Modem_power */ + {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ + {0x38,0,0}, /* FEATURE_Sound_Power */ + {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ + {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */ }; /* definition of a feature controller object */ -struct feature_controller -{ - u32* bits; +struct feature_controller { + fbit* bits; volatile u32* reg; struct device_node* device; + spinlock_t lock; }; /* static functions */ static void -feature_add_controller(struct device_node *controller_device, u32* bits); +feature_add_controller(struct device_node *controller_device, fbit* bits); -static int +static struct feature_controller* feature_lookup_controller(struct device_node *device); /* static varialbles */ -static struct feature_controller controllers[MAX_FEATURE_REGS]; +static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS]; static int controller_count = 0; @@ -96,18 +155,23 @@ struct device_node *np; np = find_devices("mac-io"); - while (np != NULL) - { - feature_add_controller(np, feature_bits_heathrow); + while (np != NULL) { + /* KeyLargo contains several (5 ?) FCR registers in mac-io, + * plus some gpio's which could eventually be handled here. + */ + if (device_is_compatible(np, "Keylargo")) { + feature_add_controller(np, feature_bits_keylargo); + } else { + feature_add_controller(np, feature_bits_heathrow); + } np = np->next; } if (controller_count == 0) { np = find_devices("ohare"); - if (np) - { + if (np) { if (find_devices("via-pmu") != NULL) - feature_add_controller(np, feature_bits_pbook); + feature_add_controller(np, feature_bits_ohare_pbook); else /* else not sure; maybe this is a Starmax? */ feature_add_controller(np, NULL); @@ -116,17 +180,26 @@ if (controller_count) printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); + +#ifdef CONFIG_PMAC_PBOOK +#ifdef CONFIG_DMASOUND_MODULE + /* On PowerBooks, we disable the sound chip when dmasound is a module */ + if (controller_count && find_devices("via-pmu") != NULL) { + feature_clear(controllers[0].device, FEATURE_Sound_power); + feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable); + } +#endif +#endif } static void -feature_add_controller(struct device_node *controller_device, u32* bits) +feature_add_controller(struct device_node *controller_device, fbit* bits) { struct feature_controller* controller; - if (controller_count >= MAX_FEATURE_REGS) - { + if (controller_count >= MAX_FEATURE_CONTROLLERS) { printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n", - controller_device->full_name, MAX_FEATURE_REGS); + controller_device->full_name, MAX_FEATURE_CONTROLLERS); return; } controller = &controllers[controller_count]; @@ -140,30 +213,32 @@ } controller->reg = (volatile u32 *)ioremap( - controller_device->addrs[0].address + OHARE_FEATURE_REG, 4); + controller_device->addrs[0].address, MAX_FEATURE_OFFSET); if (bits == NULL) { printk(KERN_INFO "Twiddling the magic ohare bits\n"); - out_le32(controller->reg, STARMAX_FEATURES); + out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES); return; } + spin_lock_init(&controller->lock); + controller_count++; } -static int +static struct feature_controller* feature_lookup_controller(struct device_node *device) { int i; if (device == NULL) - return -EINVAL; + return NULL; while(device) { for (i=0; iparent; } @@ -172,35 +247,36 @@ device->name); #endif - return -ENODEV; + return NULL; } int feature_set(struct device_node* device, enum system_feature f) { - int controller; - unsigned long flags; + struct feature_controller* controller; + unsigned long flags; + unsigned long value; + fbit* bit; if (f >= FEATURE_last) return -EINVAL; controller = feature_lookup_controller(device); - if (controller < 0) - return controller; + if (!controller) + return -ENODEV; + bit = &controller->bits[f]; #ifdef DEBUG_FEATURE printk("feature: <%s> setting feature %d in controller @0x%x\n", - device->name, (int)f, (unsigned int)controllers[controller].reg); + device->name, (int)f, (unsigned int)controller->reg); #endif - save_flags(flags); - cli(); - out_le32( controllers[controller].reg, - in_le32(controllers[controller].reg) | - controllers[controller].bits[f]); - (void)in_le32(controllers[controller].reg); - restore_flags(flags); - udelay(10); + spin_lock_irqsave(&controller->lock, flags); + value = in_le32(FREG(controller, bit->reg)); + value = bit->polarity ? (value & ~bit->mask) : (value | bit->mask); + out_le32(FREG(controller, bit->reg), value); + (void)in_le32(FREG(controller, bit->reg)); + spin_unlock_irqrestore(&controller->lock, flags); return 0; } @@ -208,29 +284,30 @@ int feature_clear(struct device_node* device, enum system_feature f) { - int controller; - unsigned long flags; + struct feature_controller* controller; + unsigned long flags; + unsigned long value; + fbit* bit; if (f >= FEATURE_last) return -EINVAL; controller = feature_lookup_controller(device); - if (controller < 0) - return controller; + if (!controller) + return -ENODEV; + bit = &controller->bits[f]; #ifdef DEBUG_FEATURE printk("feature: <%s> clearing feature %d in controller @0x%x\n", - device->name, (int)f, (unsigned int)controllers[controller].reg); + device->name, (int)f, (unsigned int)controller->reg); #endif - save_flags(flags); - cli(); - out_le32( controllers[controller].reg, - in_le32(controllers[controller].reg) & - ~(controllers[controller].bits[f])); - (void)in_le32(controllers[controller].reg); - restore_flags(flags); - udelay(10); + spin_lock_irqsave(&controller->lock, flags); + value = in_le32(FREG(controller, bit->reg)); + value = bit->polarity ? (value | bit->mask) : (value & ~bit->mask); + out_le32(FREG(controller, bit->reg), value); + (void)in_le32(FREG(controller, bit->reg)); + spin_unlock_irqrestore(&controller->lock, flags); return 0; } @@ -238,16 +315,27 @@ int feature_test(struct device_node* device, enum system_feature f) { - int controller; + struct feature_controller* controller; + unsigned long value; + fbit* bit; if (f >= FEATURE_last) return -EINVAL; controller = feature_lookup_controller(device); - if (controller < 0) - return controller; + if (!controller) + return -ENODEV; + bit = &controller->bits[f]; - return (in_le32(controllers[controller].reg) & - controllers[controller].bits[f]) != 0; +#ifdef DEBUG_FEATURE + printk("feature: <%s> clearing feature %d in controller @0x%x\n", + device->name, (int)f, (unsigned int)controller->reg); +#endif + /* If one feature contains several bits, all of them must be set + * for value to be true, or all of them must be 0 if polarity is + * inverse + */ + value = (in_le32(FREG(controller, bit->reg)) & bit->mask); + return bit->polarity ? (value == 0) : (value == bit->mask); } diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/galaxy_pci.c linux/arch/ppc/kernel/galaxy_pci.c --- v2.3.42/linux/arch/ppc/kernel/galaxy_pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/galaxy_pci.c Thu Feb 10 12:37:51 2000 @@ -0,0 +1,102 @@ +/* + * + * Copyright (c) 2000 Grant Erickson + * All rights reserved. + * + * Module name: galaxy_pci.c + * + * Description: + * PCI interface code for the IBM PowerPC 405GP on-chip PCI bus + * interface. + * + * Why is this file called "galaxy_pci"? Because on the original + * IBM "Walnut" evaluation board schematic I have, the 405GP is + * is labeled "GALAXY". + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pci.h" + + +/* Preprocessor Defines */ + +#define PCICFGADDR (volatile unsigned int *)(0xEEC00000) +#define PCICFGDATA (volatile unsigned int *)(0xEEC00004) + + +/* Function Prototypes */ + +decl_config_access_method(galaxy); + + +void __init +galaxy_pcibios_fixup(void) +{ + +} + +void __init +galaxy_setup_pci_ptrs(void) +{ + set_config_access_method(galaxy); + + ppc_md.pcibios_fixup = galaxy_pcibios_fixup; +} + +int +galaxy_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char *val) +{ + + return (PCIBIOS_SUCCESSFUL); +} + +int +galaxy_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val) +{ + + return (PCIBIOS_SUCCESSFUL); +} + +int +galaxy_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int *val) +{ + + return (PCIBIOS_SUCCESSFUL); +} + +int +galaxy_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned char val) +{ + + return (PCIBIOS_SUCCESSFUL); +} + +int +galaxy_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val) +{ + + return (PCIBIOS_SUCCESSFUL); +} + +int +galaxy_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned int val) +{ + + return (PCIBIOS_SUCCESSFUL); +} diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c --- v2.3.42/linux/arch/ppc/kernel/gemini_setup.c Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/gemini_setup.c Wed Feb 9 19:43:47 2000 @@ -53,7 +53,7 @@ }; int chrp_get_irq(struct pt_regs *); -void chrp_post_irq(int); +void chrp_post_irq(struct pt_regs* regs, int); static inline unsigned long _get_HID1(void) { @@ -132,6 +132,19 @@ extern int root_mountflags; extern char cmd_line[]; +void +gemini_heartbeat(void) +{ + static unsigned long led = GEMINI_LEDBASE+(4*8); + static char direction = 8; + *(char *)led = 0; + if ( (led + direction) > (GEMINI_LEDBASE+(7*8)) || + (led + direction) < (GEMINI_LEDBASE+(4*8)) ) + direction *= -1; + led += direction; + *(char *)led = 0xff; + ppc_md.heartbeat_count = ppc_md.heartbeat_reset; +} void __init gemini_setup_arch(void) { @@ -175,6 +188,10 @@ printk("CPU manufacturer: %s [rev=%04x]\n", (cpu & (1<<15)) ? "IBM" : "Motorola", (cpu & 0xffff)); + ppc_md.heartbeat = gemini_heartbeat; + ppc_md.heartbeat_reset = HZ/8; + ppc_md.heartbeat_count = 1; + /* take special pains to map the MPIC, since it isn't mapped yet */ gemini_openpic_init(); /* start the L2 */ @@ -505,7 +522,7 @@ return irq; } -void gemini_post_irq(int irq) +void gemini_post_irq(struct pt_regs* regs, int irq) { /* * If it's an i8259 irq then we've already done the diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.3.42/linux/arch/ppc/kernel/head.S Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/kernel/head.S Wed Feb 9 19:43:47 2000 @@ -156,6 +156,16 @@ bl fix_mem_constants #endif /* CONFIG_APUS */ +#ifndef CONFIG_GEMINI +/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains + * the physical address we are running at, returned by prom_init() + */ +__after_prom_start: + bl mmu_off + bl clear_bats + bl flush_tlbs +#endif + /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely @@ -211,6 +221,11 @@ mtspr DBAT0U,r11 /* bit in upper BAT register */ mtspr IBAT0L,r8 mtspr IBAT0U,r11 +#if 0 /* Useful debug code, please leave in for now so I don't have to + * look at docs when I need to setup a BAT ; + */ + bl setup_screen_bat +#endif 5: isync #ifndef CONFIG_APUS @@ -627,12 +642,8 @@ mtcrf 0x80,r3 rfi -/* Instruction address breakpoint exception (on 603/604) */ STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) - -/* System management exception (603?) */ - STD_EXCEPTION(0x1400, Trap_14, UnknownException) - + STD_EXCEPTION(0x1400, SMI, SMIException) STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) STD_EXCEPTION(0x1700, Trap_17, TAUException) @@ -644,10 +655,7 @@ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) - - /* Run mode exception */ STD_EXCEPTION(0x2000, RunMode, RunModeException) - STD_EXCEPTION(0x2100, Trap_21, UnknownException) STD_EXCEPTION(0x2200, Trap_22, UnknownException) STD_EXCEPTION(0x2300, Trap_23, UnknownException) @@ -911,12 +919,16 @@ * the kernel image to physical address 0. */ relocate_kernel: +#if 0 /* Is this still needed ? I don't think so. It breaks new + * boot-with-mmu-off stuff + */ lis r9,0x426f /* if booted from BootX, don't */ addi r9,r9,0x6f58 /* translate source addr */ cmpw r31,r9 /* (we have to on chrp) */ beq 7f rlwinm r4,r4,0,8,31 /* translate source address */ add r4,r4,r3 /* to region mapped with BATs */ +#endif 7: addis r9,r26,klimit@ha /* fetch klimit */ lwz r25,klimit@l(r9) addis r25,r25,-KERNELBASE@h @@ -1194,14 +1206,26 @@ cmpi 0,r9,4 /* check for 604 */ cmpi 1,r9,9 /* or 604e */ cmpi 2,r9,10 /* or mach5 */ + cmpi 3,r9,8 /* check for 750 (G3) */ + cmpi 4,r9,12 /* or 7400 (G4) */ cror 2,2,6 cror 2,2,10 bne 4f ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */ bne 2,5f ori r11,r11,HID0_BTCD + b 5f +4: + cror 14,14,18 + bne 3,6f + /* We should add ABE here if we want to use Store Gathering + * and other nifty bridge features + */ + ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC /* for g3/g4, enable */ + li r3,0 + mtspr ICTC,r3 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ -4: blr +6: blr /* * Load stuff into the MMU. Intended to be called with @@ -1388,6 +1412,45 @@ #endif /* !defined(CONFIG_GEMINI) */ blr +#ifndef CONFIG_GEMINI +flush_tlbs: + lis r20, 0x1000 +1: addic. r20, r20, -0x1000 + tlbie r20 + blt 1b + sync + blr + +mmu_off: + addi r4, r3, __after_prom_start - _start + mfmsr r3 + andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ + beq 1f + ori r3,r3,MSR_DR|MSR_IR + xori r3,r3,MSR_DR|MSR_IR + mtspr SRR0,r4 + mtspr SRR1,r3 + sync + rfi +1: blr +#endif + +#if 0 /* That's useful debug stuff */ +setup_screen_bat: + lis r3, 0x9100 +#ifdef __SMP__ + ori r3,r3,0x12 +#else + ori r3,r3,0x2 +#endif + mtspr DBAT1L, r3 + mtspr IBAT1L, r3 + ori r3,r3,(BL_8M<<2)|0x2 /* set up BAT registers for 604 */ + mtspr DBAT1U, r3 + mtspr IBAT1U, r3 + blr +#endif + /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the data segment, diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/head_4xx.S linux/arch/ppc/kernel/head_4xx.S --- v2.3.42/linux/arch/ppc/kernel/head_4xx.S Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/kernel/head_4xx.S Wed Feb 9 19:43:47 2000 @@ -78,13 +78,17 @@ li r24,0 + ## Invalidate all TLB entries + + tlbia + ## We should still be executing code at physical address 0x0000xxxx ## at this point. However, start_here is at virtual address ## 0xC000xxxx. So, set up a TLB mapping to cover this once ## translation is enabled. lis r3,KERNELBASE@h # Load the kernel virtual address - addis r3,r3,KERNELBASE@l + ori r3,r3,KERNELBASE@l tophys(r4,r3) # Load the kernel physical address ## Save the existing PID and load the kernel PID. @@ -96,11 +100,7 @@ ## Configure and load entry into TLB slot 0. clrrwi r4,r4,10 # Mask off the real page number - - ## XXX - Temporarily set the TLB_I bit because of cache issues that - ## seem to foul-up the exception handling code. - - ori r4,r4,(TLB_WR | TLB_EX | TLB_I) # Set the write and execute bits + ori r4,r4,(TLB_WR | TLB_EX) # Set the write and execute bits clrrwi r3,r3,10 # Mask off the effective page number ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) @@ -333,22 +333,12 @@ #endif ### 0x1100 - Data TLB Miss Exception - - START_EXCEPTION(0x1100, DTLBMiss) - STND_EXCEPTION_PROLOG - addi r3,r1,STACK_FRAME_OVERHEAD - li r7,STND_EXC - li r20,MSR_KERNEL - FINISH_EXCEPTION(UnknownException) + + STND_EXCEPTION(0x1100, DTLBMiss, PPC4xx_dtlb_miss) ### 0x1200 - Instruction TLB Miss Exception - - START_EXCEPTION(0x1200, ITLBMiss) - STND_EXCEPTION_PROLOG - addi r3,r1,STACK_FRAME_OVERHEAD - li r7,STND_EXC - li r20,MSR_KERNEL - FINISH_EXCEPTION(UnknownException) + + STND_EXCEPTION(0x1200, ITLBMiss, PPC4xx_itlb_miss) STND_EXCEPTION(0x1300, Trap_13, UnknownException) STND_EXCEPTION(0x1400, Trap_14, UnknownException) @@ -560,8 +550,6 @@ _GLOBAL(set_context) mtspr SPRN_PID,r3 - tlbia - SYNC blr ### diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.3.42/linux/arch/ppc/kernel/idle.c Wed Oct 27 16:34:12 1999 +++ linux/arch/ppc/kernel/idle.c Wed Feb 9 19:43:47 2000 @@ -154,11 +154,12 @@ if ( zero_quicklist ) { /* atomically remove this page from the list */ - asm ( "101:lwarx %1,0,%2\n" /* reserve zero_cache */ + register unsigned long tmp; + asm ( "101:lwarx %1,0,%3\n" /* reserve zero_cache */ " lwz %0,0(%1)\n" /* get next -- new zero_cache */ - " stwcx. %0,0,%2\n" /* update zero_cache */ + " stwcx. %0,0,%3\n" /* update zero_cache */ " bne- 101b\n" /* if lost reservation try again */ - : "=&r" (zero_quicklist), "=&r" (page) + : "=&r" (tmp), "=&r" (page), "+m" (zero_cache) : "r" (&zero_quicklist) : "cc" ); #ifdef __SMP__ @@ -193,6 +194,7 @@ { unsigned long pageptr = 0; /* current page being zero'd */ unsigned long bytecount = 0; + register unsigned long tmp; pte_t *pte; if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] ) @@ -249,15 +251,14 @@ pte_cache(*pte); flush_tlb_page(find_vma(&init_mm,pageptr),pageptr); /* atomically add this page to the list */ - asm ( "101:lwarx %0,0,%1\n" /* reserve zero_cache */ - " stw %0,0(%2)\n" /* update *pageptr */ + asm ( "101:lwarx %0,0,%2\n" /* reserve zero_cache */ + " stw %0,0(%3)\n" /* update *pageptr */ #ifdef __SMP__ " sync\n" /* let store settle */ #endif - " mr %0,%2\n" /* update zero_cache in reg */ - " stwcx. %2,0,%1\n" /* update zero_cache in mem */ + " stwcx. %3,0,%2\n" /* update zero_cache in mem */ " bne- 101b\n" /* if lost reservation try again */ - : "=&r" (zero_quicklist) + : "=&r" (tmp), "+m" (zero_quicklist) : "r" (&zero_quicklist), "r" (pageptr) : "cc" ); /* diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.3.42/linux/arch/ppc/kernel/irq.c Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/irq.c Wed Feb 9 19:43:47 2000 @@ -126,7 +126,7 @@ */ int request_8xxirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), #elif defined(CONFIG_APUS) -int sys_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), +int request_sysirq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), #else int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), #endif @@ -315,7 +315,7 @@ } ppc_irq_dispatch_handler( regs, irq ); if ( ppc_md.post_irq ) - ppc_md.post_irq( irq ); + ppc_md.post_irq( regs, irq ); out: hardirq_exit( cpu ); diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/local_irq.h linux/arch/ppc/kernel/local_irq.h --- v2.3.42/linux/arch/ppc/kernel/local_irq.h Wed Dec 29 13:13:12 1999 +++ linux/arch/ppc/kernel/local_irq.h Wed Feb 9 19:43:47 2000 @@ -4,6 +4,8 @@ #include #include +#include +#include #include void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.3.42/linux/arch/ppc/kernel/misc.S Fri Jan 28 15:09:07 2000 +++ linux/arch/ppc/kernel/misc.S Wed Feb 9 19:43:47 2000 @@ -20,13 +20,13 @@ #include #include "ppc_asm.h" -#ifndef CONFIG_8xx -CACHE_LINE_SIZE = 32 -LG_CACHE_LINE_SIZE = 5 -#else +#if defined(CONFIG_4xx) || defined(CONFIG_8xx) CACHE_LINE_SIZE = 16 LG_CACHE_LINE_SIZE = 4 -#endif /* CONFIG_8xx */ +#else +CACHE_LINE_SIZE = 32 +LG_CACHE_LINE_SIZE = 5 +#endif /* CONFIG_4xx || CONFIG_8xx */ .text @@ -590,6 +590,20 @@ _GLOBAL(_get_PVR) mfspr r3,PVR blr + +_GLOBAL(_get_HID0) + mfspr r3,HID0 + blr + +_GLOBAL(_get_ICTC) + mfspr r3,ICTC + blr + +_GLOBAL(_set_ICTC) + mtspr ICTC,r3 + blr + + /* L2CR functions Copyright © 1997-1998 by PowerLogix R & D, Inc. @@ -656,6 +670,8 @@ rlwinm r4,r4,16,16,31 cmplwi r4,0x0008 beq thisIs750 + cmplwi r4,0x000c + beq thisIs750 li r3,-1 blr @@ -750,9 +766,11 @@ mfspr r3,PVR rlwinm r3,r3,16,16,31 cmplwi r3,0x0008 + beq 1f + cmplwi r3,0x000c li r3,0 bnelr - +1: /* Return the L2CR contents */ mfspr r3,L2CR blr diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/oak_setup.c linux/arch/ppc/kernel/oak_setup.c --- v2.3.42/linux/arch/ppc/kernel/oak_setup.c Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/oak_setup.c Wed Feb 9 19:43:47 2000 @@ -1,6 +1,6 @@ /* * - * Copyright (c) 1999 Grant Erickson + * Copyright (c) 1999-2000 Grant Erickson * * Module name: oak_setup.c * @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,12 @@ #include "time.h" #include "oak_setup.h" + + + + + + /* Function Prototypes */ extern void abort(void); @@ -95,32 +102,32 @@ /* Initialize machine-dependency vectors */ - ppc_md.setup_arch = oak_setup_arch; - ppc_md.setup_residual = oak_setup_residual; - ppc_md.get_cpuinfo = NULL; - ppc_md.irq_cannonicalize = NULL; - ppc_md.init_IRQ = oak_init_IRQ; - ppc_md.get_irq = oak_get_irq; - ppc_md.init = NULL; - - ppc_md.restart = oak_restart; - ppc_md.power_off = oak_power_off; - ppc_md.halt = oak_halt; - - ppc_md.time_init = oak_time_init; - ppc_md.set_rtc_time = oak_set_rtc_time; - ppc_md.get_rtc_time = oak_get_rtc_time; - ppc_md.calibrate_decr = oak_calibrate_decr; - - ppc_md.kbd_setkeycode = NULL; - ppc_md.kbd_getkeycode = NULL; - ppc_md.kbd_translate = NULL; - ppc_md.kbd_unexpected_up = NULL; - ppc_md.kbd_leds = NULL; - ppc_md.kbd_init_hw = NULL; + ppc_md.setup_arch = oak_setup_arch; + ppc_md.setup_residual = oak_setup_residual; + ppc_md.get_cpuinfo = NULL; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = oak_init_IRQ; + ppc_md.get_irq = oak_get_irq; + ppc_md.init = NULL; + + ppc_md.restart = oak_restart; + ppc_md.power_off = oak_power_off; + ppc_md.halt = oak_halt; + + ppc_md.time_init = oak_time_init; + ppc_md.set_rtc_time = oak_set_rtc_time; + ppc_md.get_rtc_time = oak_get_rtc_time; + ppc_md.calibrate_decr = oak_calibrate_decr; + + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; #if defined(CONFIG_MAGIC_SYSRQ) - ppc_md.kbd_sysrq_xlate = NULL; + ppc_md.ppc_kbd_sysrq_xlate = NULL; #endif return; diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/oak_setup.h linux/arch/ppc/kernel/oak_setup.h --- v2.3.42/linux/arch/ppc/kernel/oak_setup.h Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/oak_setup.h Wed Feb 9 19:43:47 2000 @@ -1,14 +1,14 @@ /* * - * Copyright (c) 1999 Grant Erickson + * Copyright (c) 1999-2000 Grant Erickson * - * Module name: oak_setup.c + * Module name: oak_setup.h * * Description: * Architecture- / platform-specific boot-time initialization code for * the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original * code by Gary Thomas, Cort Dougan , and Dan Malek - * . + * . * */ diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.3.42/linux/arch/ppc/kernel/open_pic.c Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/open_pic.c Thu Feb 10 12:37:22 2000 @@ -8,6 +8,7 @@ * for more details. */ +#include #include #include #include @@ -17,17 +18,30 @@ #include #include #include +#include #include "local_irq.h" volatile struct OpenPIC *OpenPIC = NULL; u_int OpenPIC_NumInitSenses __initdata = 0; u_char *OpenPIC_InitSenses __initdata = NULL; +int open_pic_irq_offset; +extern int use_of_interrupt_tree; void chrp_mask_irq(unsigned int); void chrp_unmask_irq(unsigned int); +void find_ISUs(void); static u_int NumProcessors; static u_int NumSources; +OpenPIC_Source *ISU; +/* + * We should use this if we have > 1 ISU. + * We can just point each entry to the + * appropriate source regs but it wastes a lot of space + * so until we have >1 ISU I'll leave it unimplemented. + * -- Cort +OpenPIC_Source ISU[128]; +*/ struct hw_interrupt_type open_pic = { " OpenPIC ", @@ -38,7 +52,6 @@ 0, 0 }; -int open_pic_irq_offset; /* * Accesses to the current processor's registers @@ -96,7 +109,7 @@ #endif /* __SMP__ */ #ifdef __i386__ -static inline u_int ld_le32(volatile u_int *addr) +static inline u_int in_le32(volatile u_int *addr) { return *addr; } @@ -111,7 +124,7 @@ { u_int val; - val = ld_le32(addr); + val = in_le32(addr); return val; } @@ -148,6 +161,9 @@ { openpic_setfield(addr, OPENPIC_MASK); /* wait until it's not in use */ + /* BenH: Is this code really enough ? I would rather check the result + * and eventually retry ... + */ while (openpic_read(addr) & OPENPIC_ACTIVITY); openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK); } @@ -182,16 +198,18 @@ OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1; NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; - - printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version, - NumProcessors, NumSources, OpenPIC); - timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); - printk("OpenPIC timer frequency is "); - if (timerfreq) - printk("%d Hz\n", timerfreq); - else - printk("not set\n"); - + if ( _machine != _MACH_Pmac ) + { + printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version, + NumProcessors, NumSources, OpenPIC); + timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency); + printk("OpenPIC timer frequency is "); + if (timerfreq) + printk("%d MHz\n", timerfreq>>20); + else + printk("not set\n"); + } + if ( main_pic ) { /* Initialize timer interrupts */ @@ -209,24 +227,59 @@ /* Disabled, Priority 8 */ openpic_initipi(i, 8, OPENPIC_VEC_IPI+i); } - - /* Initialize external interrupts */ - if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc); - /* SIOint (8259 cascade) is special */ - openpic_initirq(0, 8, open_pic_irq_offset, 1, 1); - openpic_mapirq(0, 1<<0); - for (i = 1; i < NumSources; i++) { - /* Enabled, Priority 8 */ - openpic_initirq(i, 8, open_pic_irq_offset+i, 0, - i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); - /* Processor 0 */ - openpic_mapirq(i, 1<<0); + find_ISUs(); + if ( _machine != _MACH_Pmac ) + { + /* Initialize external interrupts */ + if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc); + /* SIOint (8259 cascade) is special */ + openpic_initirq(0, 8, open_pic_irq_offset, 1, 1); + openpic_mapirq(0, 1<<0); + for (i = 1; i < NumSources; i++) { + /* Enabled, Priority 8 */ + openpic_initirq(i, 8, open_pic_irq_offset+i, 0, + i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); + /* Processor 0 */ + openpic_mapirq(i, 1<<0); + } } - + else + { + /* Prevent any interrupt from occuring during initialisation. + * Hum... I believe this is not necessary, Apple does that in + * Darwin's PowerExpress code. + */ + openpic_set_priority(0, 0xf); + + /* First disable all interrupts and map them to CPU 0 */ + for (i = 0; i < NumSources; i++) { + openpic_disable_irq(i); + openpic_mapirq(i, 1<<0); + } + + /* If we use the device tree, then lookup all interrupts and + * initialize them according to sense infos found in the tree + */ + if (use_of_interrupt_tree) { + struct device_node* np = find_all_nodes(); + while(np) { + int j, pri; + pri = strcmp(np->name, "programmer-switch") ? 2 : 7; + for (j=0;jn_intrs;j++) + openpic_initirq( np->intrs[j].line, + pri, + np->intrs[j].line, + np->intrs[j].sense, + np->intrs[j].sense); + np = np->next; + } + } + } + /* Initialize the spurious interrupt */ if ( ppc_md.progress ) ppc_md.progress("openpic spurious",0x3bd); openpic_set_spurious(OPENPIC_VEC_SPURIOUS); - if ( _machine != _MACH_gemini ) + if ( !(_machine && (_MACH_gemini|_MACH_Pmac)) ) { if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, "82c59 cascade", NULL)) @@ -238,6 +291,20 @@ if ( ppc_md.progress ) ppc_md.progress("openpic exit",0x222); } +void find_ISUs(void) +{ +#ifdef CONFIG_PPC64 + /* hardcode this for now since the IBM 260 is the only thing with + * a distributed openpic right now. -- Cort + */ + ISU = (OpenPIC_Source *)0xfeff7c00; + NumSources = 0x10; +#else + /* for non-distributed OpenPIC implementations it's in the IDU -- Cort */ + ISU = OpenPIC->Source; +#endif +} + void openpic_reset(void) { openpic_setfield(&OpenPIC->Global.Global_Configuration0, @@ -279,6 +346,8 @@ { check_arg_cpu(cpu); openpic_write(&OpenPIC->THIS_CPU.EOI, 0); + /* Handle PCI write posting */ + (void)openpic_read(&OpenPIC->THIS_CPU.EOI); } @@ -379,7 +448,7 @@ #if 0 /* let the openpic know we want intrs */ for ( i = 0; i < NumSources ; i++ ) - openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination) + openpic_mapirq(i, openpic_read(ISU[i].Destination) | (1<Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK); + openpic_clearfield(&ISU[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK); + /* make sure mask gets to controller before we return to user */ + do { + mb(); /* sync is probably useless here */ + } while(openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_MASK)); } void openpic_disable_irq(u_int irq) { check_arg_irq(irq); - openpic_setfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK); + openpic_setfield(&ISU[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK); + /* make sure mask gets to controller before we return to user */ + do { + mb(); /* sync is probably useless here */ + } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_MASK)); } /* @@ -440,12 +519,13 @@ check_arg_irq(irq); check_arg_pri(pri); check_arg_vec(vec); - openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, + openpic_safe_writefield(&ISU[irq].Vector_Priority, OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK | - OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL, + OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK, (pri << OPENPIC_PRIORITY_SHIFT) | vec | - (pol ? OPENPIC_SENSE_POLARITY : 0) | - (sense ? OPENPIC_SENSE_LEVEL : 0)); + (pol ? OPENPIC_POLARITY_POSITIVE : + OPENPIC_POLARITY_NEGATIVE) | + (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE)); } /* @@ -454,7 +534,7 @@ void openpic_mapirq(u_int irq, u_int cpumask) { check_arg_irq(irq); - openpic_write(&OpenPIC->Source[irq].Destination, cpumask); + openpic_write(&ISU[irq].Destination, cpumask); } /* @@ -465,7 +545,7 @@ void openpic_set_sense(u_int irq, int sense) { check_arg_irq(irq); - openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority, + openpic_safe_writefield(&ISU[irq].Vector_Priority, OPENPIC_SENSE_LEVEL, (sense ? OPENPIC_SENSE_LEVEL : 0)); } diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/pci-dma.c linux/arch/ppc/kernel/pci-dma.c --- v2.3.42/linux/arch/ppc/kernel/pci-dma.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/pci-dma.c Wed Feb 9 19:43:47 2000 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2000 Ani Joshi + * + * + * Dynamic DMA mapping support. + * + * swiped from i386 + * + */ + +#include +#include +#include +#include +#include + +/* Pure 2^n version of get_order */ +extern __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; +} + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + + if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, __get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, __get_order(size)); +} diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.3.42/linux/arch/ppc/kernel/pci.c Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/pci.c Wed Feb 9 19:43:47 2000 @@ -71,9 +71,9 @@ { printk("PCI: Probing PCI hardware\n"); pci_scan_bus(0, &generic_pci_ops, NULL); - pcibios_claim_resources(&pci_root_buses); if (ppc_md.pcibios_fixup) ppc_md.pcibios_fixup(); + pcibios_claim_resources(&pci_root_buses); } void __init diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/pmac_nvram.c linux/arch/ppc/kernel/pmac_nvram.c --- v2.3.42/linux/arch/ppc/kernel/pmac_nvram.c Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/pmac_nvram.c Wed Feb 9 19:43:47 2000 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -20,23 +21,37 @@ static int nvram_naddrs; static volatile unsigned char *nvram_addr; static volatile unsigned char *nvram_data; -static int nvram_mult; - -#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ - +static int nvram_mult, is_core_99; +static char* nvram_image; + +#define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ + __init void pmac_nvram_init(void) { struct device_node *dp; + nvram_naddrs = 0; + dp = find_devices("nvram"); if (dp == NULL) { printk(KERN_ERR "Can't find NVRAM device\n"); - nvram_naddrs = 0; return; } nvram_naddrs = dp->n_addrs; - if (_machine == _MACH_chrp && nvram_naddrs == 1) { + is_core_99 = device_is_compatible(dp, "nvram,flash"); + if (is_core_99) + { + int i; + if (nvram_naddrs < 1) + return; + nvram_image = kmalloc(dp->addrs[0].size, GFP_KERNEL); + if (!nvram_image) + return; + nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); + for (i=0; iaddrs[0].size; i++) + nvram_image[i] = in_8(nvram_data + i); + } else if (_machine == _MACH_chrp && nvram_naddrs == 1) { nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size); nvram_mult = 1; } else if (nvram_naddrs == 1) { @@ -69,6 +84,8 @@ return req.reply[1]; #endif case 1: + if (is_core_99) + return nvram_image[addr]; return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]; case 2: *nvram_addr = addr >> 5; @@ -94,6 +111,10 @@ break; #endif case 1: + if (is_core_99) { + nvram_image[addr] = val; + break; + } nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val; break; case 2: diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.3.42/linux/arch/ppc/kernel/pmac_pci.c Thu Jan 6 12:57:47 2000 +++ linux/arch/ppc/kernel/pmac_pci.c Wed Feb 9 19:43:47 2000 @@ -30,6 +30,16 @@ struct bridge_data **bridges, *bridge_list; static int max_bus; +struct uninorth_data { + struct device_node* node; + volatile unsigned int* cfg_addr; + volatile unsigned int* cfg_data; +}; + +static struct uninorth_data uninorth_bridges[3]; +static int uninorth_count; +static int uninorth_default = -1; + static void add_bridges(struct device_node *dev); /* @@ -73,6 +83,159 @@ return 0; } +/* This function only works for bus 0, uni-N uses a different mecanism for + * other busses (see below) + */ +#define UNI_N_CFA0(devfn, off) \ + ((1 << (unsigned long)PCI_SLOT(dev_fn)) \ + | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \ + | (((unsigned long)(off)) & 0xFCUL)) + +/* This one is for type 1 config accesses */ +#define UNI_N_CFA1(bus, devfn, off) \ + ((((unsigned long)(bus)) << 16) \ + |(((unsigned long)(devfn)) << 8) \ + |(((unsigned long)(off)) & 0xFCUL) \ + |1UL) + +/* We should really use RTAS here, unfortunately, it's not available with BootX. + * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff + * later, once I have something that works enough with BootX. + */ +__pmac static +unsigned int +uni_north_access_data(unsigned char bus, unsigned char dev_fn, + unsigned char offset) +{ + struct device_node *node, *bridge_node; + int bridge = uninorth_default; + unsigned int caddr; + + if (bus == 0) { + if (PCI_SLOT(dev_fn) < 11) { + return 0; + } + /* We look for the OF device corresponding to this bus/devfn pair. If we + * don't find it, we default to the external PCI */ + bridge_node = NULL; + node = find_pci_device_OFnode(bus, dev_fn & 0xf8); + if (node) { + /* note: we don't stop on the first occurence since we need to go + * up to the root bridge */ + do { + if (!strcmp(node->type, "pci")) + bridge_node = node; + node=node->parent; + } while (node); + } + if (bridge_node) { + int i; + for (i=0;iio_base); } +#define GRACKLE_STG_ENABLE 0x00000040 + +/* N.B. this is called before bridges is initialized, so we can't + use grackle_pcibios_{read,write}_config_dword. */ +static inline void grackle_set_stg(struct bridge_data *bp, int enable) +{ + unsigned int val; + + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + val = in_le32((volatile unsigned int *)bp->cfg_data); + val = enable? (val | GRACKLE_STG_ENABLE): (val & ~GRACKLE_STG_ENABLE); + out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); + out_le32((volatile unsigned int *)bp->cfg_data, val); +} + void __init pmac_find_bridges(void) { int bus; @@ -411,20 +589,47 @@ printk(KERN_INFO "PCI buses %d..%d", bus_range[0], bus_range[1]); printk(" controlled by %s at %x\n", dev->name, addr->address); + if (device_is_compatible(dev, "uni-north")) { + int i = uninorth_count++; + uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000); + uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000); + uninorth_bridges[i].node = dev; + /* XXX This is the bridge with the PCI expansion bus. This is also the + * address of the bus that will receive type 1 config accesses and io + * accesses. Appears to be correct for iMac DV and G4 Sawtooth too. + * That means that we cannot do io cycles on the AGP bus nor the internal + * ethernet/fw bus. Fortunately, they appear not to be needed on iMac DV + * and G4 neither. + */ + if (addr->address == 0xf2000000) + uninorth_default = i; + else + continue; + } + bp = (struct bridge_data *) alloc_bootmem(sizeof(*bp)); - if (strcmp(dev->name, "pci") != 0) { - bp->cfg_addr = (volatile unsigned int *) - ioremap(addr->address + 0x800000, 0x1000); - bp->cfg_data = (volatile unsigned char *) - ioremap(addr->address + 0xc00000, 0x1000); - bp->io_base = (void *) ioremap(addr->address, 0x10000); - } else { - /* XXX */ + if (device_is_compatible(dev, "uni-north")) { + bp->cfg_addr = 0; + bp->cfg_data = 0; + /* is 0x10000 enough for io space ? */ + bp->io_base = (void *)ioremap(addr->address, 0x10000); + } else if (strcmp(dev->name, "pci") == 0) { + /* XXX assume this is a mpc106 (grackle) */ bp->cfg_addr = (volatile unsigned int *) ioremap(0xfec00000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); bp->io_base = (void *) ioremap(0xfe000000, 0x20000); +#if 0 /* Disabled for now, HW problems */ + grackle_set_stg(bp, 1); +#endif + } else { + /* a `bandit' or `chaos' bridge */ + bp->cfg_addr = (volatile unsigned int *) + ioremap(addr->address + 0x800000, 0x1000); + bp->cfg_data = (volatile unsigned char *) + ioremap(addr->address + 0xc00000, 0x1000); + bp->io_base = (void *) ioremap(addr->address, 0x10000); } if (isa_io_base == 0) isa_io_base = (unsigned long) bp->io_base; @@ -453,7 +658,7 @@ for (; node != 0;node = node->sibling) { class_code = (unsigned int *) get_property(node, "class-code", 0); - if((*class_code >> 8) == PCI_CLASS_BRIDGE_PCI) + if(class_code && (*class_code >> 8) == PCI_CLASS_BRIDGE_PCI) fix_intr(node->child, dev); reg = (unsigned int *) get_property(node, "reg", 0); if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn) @@ -490,20 +695,38 @@ if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) || !pin) continue; /* No interrupt generated -> no fixup */ - fix_intr(bp->node->child, dev); + /* We iterate all instances of uninorth for now */ + if (uninorth_count && dev->bus->number == 0) { + int i; + for (i=0;ichild, dev); + } else + fix_intr(bp->node->child, dev); } } void __init pmac_setup_pci_ptrs(void) { - if (find_devices("pci") != 0) { - /* looks like a G3 powermac */ - set_config_access_method(grackle); - } else { + struct device_node* np; + + np = find_devices("pci"); + if (np != 0) + { + if (device_is_compatible(np, "uni-north")) + { + /* looks like an Core99 powermac */ + set_config_access_method(uni); + } else + { + /* looks like a G3 powermac */ + set_config_access_method(grackle); + } + } else + { set_config_access_method(pmac); } - + ppc_md.pcibios_fixup = pmac_pcibios_fixup; } diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.3.42/linux/arch/ppc/kernel/pmac_pic.c Wed Dec 29 13:13:12 1999 +++ linux/arch/ppc/kernel/pmac_pic.c Wed Feb 9 19:43:47 2000 @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -27,12 +29,38 @@ static int max_irqs; static int max_real_irqs; +static int has_openpic = 0; #define MAXCOUNT 10000000 #define GATWICK_IRQ_POOL_SIZE 10 static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; +extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short *val); +extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, + unsigned char offset, unsigned short val); + +static void pmac_openpic_mask_irq(unsigned int irq_nr) +{ + openpic_disable_irq(irq_nr); +} + +static void pmac_openpic_unmask_irq(unsigned int irq_nr) +{ + openpic_enable_irq(irq_nr); +} + +struct hw_interrupt_type pmac_open_pic = { + " OpenPIC ", + NULL, + NULL, + pmac_openpic_unmask_irq, + pmac_openpic_mask_irq, + pmac_openpic_mask_irq, + 0 +}; + static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); @@ -141,74 +169,6 @@ ppc_irq_dispatch_handler( regs, irq ); } -#if 0 -void -pmac_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) -{ - int irq; - unsigned long bits = 0; - -#ifdef __SMP__ - /* IPI's are a hack on the powersurge -- Cort */ - if ( cpu != 0 ) - { -#ifdef CONFIG_XMON - static int xmon_2nd; - if (xmon_2nd) - xmon(regs); -#endif - pmac_smp_message_recv(); - return -1; - } - - { - unsigned int loops = MAXCOUNT; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } - } -#endif /* __SMP__ */ - - for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { - int i = irq >> 5; - bits = ld_le32(&pmac_irq_hw[i]->flag) - | ppc_lost_interrupts[i]; - if (bits == 0) - continue; - irq -= cntlzw(bits); - break; - } - - if (irq < 0) - { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - ppc_spurious_interrupts++; - } - else - { - ppc_irq_dispatch_handler( regs, irq ); - } -#ifdef CONFIG_SMP -out: -#endif /* CONFIG_SMP */ -} -#endif - int pmac_get_irq(struct pt_regs *regs) { @@ -248,15 +208,30 @@ } #endif /* __SMP__ */ - for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { - int i = irq >> 5; - bits = ld_le32(&pmac_irq_hw[i]->flag) - | ppc_lost_interrupts[i]; - if (bits == 0) - continue; - irq -= cntlzw(bits); - break; - } + /* Yeah, I know, this could be a separate do_IRQ function */ + if (has_openpic) + { + irq = openpic_irq(smp_processor_id()); + if (irq == OPENPIC_VEC_SPURIOUS) + /* We get those when doing polled ADB requests, + * using -2 is a temp hack to disable the printk + */ + irq = -2; /*-1; */ + else + openpic_eoi(smp_processor_id()); + } + else + { + for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { + int i = irq >> 5; + bits = ld_le32(&pmac_irq_hw[i]->flag) + | ppc_lost_interrupts[i]; + if (bits == 0) + continue; + irq -= cntlzw(bits); + break; + } + } return irq; } @@ -339,6 +314,51 @@ } } +/* + * The PowerBook 3400/2400/3500 can have a combo ethernet/modem + * card which includes an ohare chip that acts as a second interrupt + * controller. If we find this second ohare, set it up and fix the + * interrupt value in the device tree for the ethernet chip. + */ +static void __init enable_second_ohare(void) +{ + unsigned char bus, devfn; + unsigned short cmd; + unsigned long addr; + int second_irq; + struct device_node *irqctrler = find_devices("pci106b,7"); + struct device_node *ether; + + if (irqctrler == NULL || irqctrler->n_addrs <= 0) + return; + addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40); + pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20); + max_irqs = 64; + if (pci_device_loc(irqctrler, &bus, &devfn) == 0) { + pmac_pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + cmd &= ~PCI_COMMAND_IO; + pmac_pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd); + } + + second_irq = irqctrler->intrs[0].line; + printk(KERN_INFO "irq: secondary controller on irq %d\n", second_irq); + request_irq(second_irq, gatwick_action, SA_INTERRUPT, + "interrupt cascade", 0 ); + + /* Fix interrupt for the modem/ethernet combo controller. The number + in the device tree (27) is bogus (correct for the ethernet-only + board but not the combo ethernet/modem board). + The real interrupt is 28 on the second controller -> 28+32 = 60. + */ + ether = find_devices("pci1011,14"); + if (ether && ether->n_intrs > 0) { + ether->intrs[0].line = 60; + printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n", + ether->intrs[0].line); + } +} + void __init pmac_pic_init(void) { @@ -347,9 +367,44 @@ unsigned long addr; int second_irq = -999; + /* We first try to detect Apple's new Core99 chipset, since mac-io + * is quite different on those machines and contains an IBM MPIC2. + */ + irqctrler = find_type_devices("open-pic"); + if (irqctrler != NULL) + { + printk("PowerMac using OpenPIC irq controller\n"); + if (irqctrler->n_addrs > 0) + { +#ifdef CONFIG_XMON + struct device_node* pswitch; +#endif /* CONFIG_XMON */ + OpenPIC = (volatile struct OpenPIC *) + ioremap(irqctrler->addrs[0].address, + irqctrler->addrs[0].size); + for ( i = 0 ; i < NR_IRQS ; i++ ) + irq_desc[i].handler = &pmac_open_pic; + openpic_init(1); + has_openpic = 1; +#ifdef CONFIG_XMON + pswitch = find_devices("programmer-switch"); + if (pswitch && pswitch->n_intrs) + request_irq(pswitch->intrs[0].line, xmon_irq, 0, + "NMI - XMON", 0); +#endif /* CONFIG_XMON */ + return; + } + irqctrler = NULL; + } - /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, - others have 32 */ + /* + * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, + * 1998 G3 Series PowerBooks have 128, + * other powermacs have 32. + * The combo ethernet/modem card for the Powerstar powerbooks + * (2400/3400/3500, ohare based) has a second ohare chip + * effectively making a total of 64. + */ max_irqs = max_real_irqs = 32; irqctrler = find_devices("mac-io"); if (irqctrler) @@ -389,6 +444,12 @@ pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20); } + /* PowerBooks 3400 and 3500 can have a second controller in a second + ohare chip, on the combo ethernet/modem card */ + if (machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500")) + enable_second_ohare(); + /* disable all interrupts in all controllers */ for (i = 0; i * 32 < max_irqs; ++i) out_le32(&pmac_irq_hw[i]->enable, 0); @@ -435,7 +496,12 @@ out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); if (max_real_irqs > 32) out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); - mb(); + (void)in_le32(&pmac_irq_hw[0]->flag); + do { + /* make sure mask gets to controller before we + return to user */ + mb(); + } while(in_le32(&pmac_irq_hw[0]->enable) != ppc_cached_irq_mask[0]); } void diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.3.42/linux/arch/ppc/kernel/pmac_setup.c Fri Jan 7 19:13:21 2000 +++ linux/arch/ppc/kernel/pmac_setup.c Wed Feb 9 19:43:47 2000 @@ -104,6 +104,10 @@ extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); static void init_p2pbridge(void); +static void init_uninorth(void); +#ifdef CONFIG_BOOTX_TEXT +void pmac_progress(char *s, unsigned short hex); +#endif __pmac int @@ -232,8 +236,10 @@ if (fp != 0) { switch (_get_PVR() >> 16) { case 4: /* 604 */ + case 8: /* G3 */ case 9: /* 604e */ case 10: /* mach V (604ev5) */ + case 12: /* G4 */ case 20: /* 620 */ loops_per_sec = *fp; break; @@ -252,9 +258,10 @@ pmac_find_bridges(); init_p2pbridge(); - + init_uninorth(); + /* Checks "l2cr-value" property in the registry */ - if ( (_get_PVR() >> 16) == 8) { + if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) { struct device_node *np = find_devices("cpus"); if (np == 0) np = find_type_devices("cpu"); @@ -346,6 +353,33 @@ } } +static void __init +init_uninorth(void) +{ + /* + * Turns on the gmac clock so that it responds to PCI cycles + * later, the driver may want to turn it off again to save + * power when interface is down + */ + struct device_node* uni_n = find_devices("uni-n"); + struct device_node* gmac = find_devices("ethernet"); + unsigned long* addr; + + if (!uni_n || uni_n->n_addrs < 1) + return; + addr = ioremap(uni_n->addrs[0].address, 0x300); + + while(gmac) { + if (device_is_compatible(gmac, "gmac")) + break; + gmac = gmac->next; + } + if (gmac) { + *(addr + 8) |= 2; + eieio(); + } +} + extern char *bootpath; extern char *bootdevice; void *boot_host; @@ -401,14 +435,11 @@ #endif #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) -extern int pmac_ide_count; -extern struct device_node *pmac_ide_node[]; -static int ide_majors[] = { 3, 22, 33, 34, 56, 57, 88, 89, 90, 91 }; kdev_t __init find_ide_boot(void) { char *p; - int i, n; + int n; if (bootdevice == NULL) return 0; @@ -417,18 +448,7 @@ return 0; n = p - bootdevice; - /* - * Look through the list of IDE interfaces for this one. - */ - for (i = 0; i < pmac_ide_count; ++i) { - char *name = pmac_ide_node[i]->full_name; - if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) { - /* XXX should cope with the 2nd drive as well... */ - return MKDEV(ide_majors[i], 0); - } - } - - return 0; + return pmac_find_ide_boot(bootdevice, n); } #endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ @@ -464,10 +484,10 @@ find_boot_device(); found_boot = 1; } - if (dev == boot_dev) { + if (boot_dev == 0 || dev == boot_dev) { ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part); boot_dev = NODEV; - printk(" (root)"); + printk(" (root on %d)", part); } } @@ -550,11 +570,15 @@ return 0; } +#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) +extern ide_ioreg_t pmac_ide_get_base(int index); +#endif + ide_ioreg_t pmac_ide_default_io_base(int index) { #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) - return pmac_ide_regbase[index]; + return pmac_ide_get_base(index); #else return 0; #endif @@ -660,5 +684,22 @@ ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; ppc_ide_md.io_base = _IO_BASE; /* actually too early for this :-( */ -#endif +#endif +#ifdef CONFIG_BOOTX_TEXT + ppc_md.progress = pmac_progress; +#endif + if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); + } + +#ifdef CONFIG_BOOTX_TEXT +extern void drawchar(char c); +extern void drawstring(const char *c); +void +pmac_progress(char *s, unsigned short hex) +{ + drawstring(s); + drawchar('\n'); +} +#endif CONFIG_BOOTX_TEXT + diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c --- v2.3.42/linux/arch/ppc/kernel/pmac_time.c Tue Jan 11 22:31:37 2000 +++ linux/arch/ppc/kernel/pmac_time.c Wed Feb 9 19:43:47 2000 @@ -71,8 +71,8 @@ if (req.reply_len != 7) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); - return (req.reply[3] << 24) + (req.reply[4] << 16) - + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET; + return (unsigned long)(req.reply[1] << 24) + (req.reply[2] << 16) + + (req.reply[3] << 8) + (unsigned long)req.reply[4] - RTC_OFFSET; #endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c --- v2.3.42/linux/arch/ppc/kernel/ppc-stub.c Tue Aug 31 17:29:13 1999 +++ linux/arch/ppc/kernel/ppc-stub.c Wed Feb 9 19:43:47 2000 @@ -351,7 +351,7 @@ static inline void set_msr(int msr) { - asm volatile("mfmsr %0" : : "r" (msr)); + asm volatile("mtmsr %0" : : "r" (msr)); } /* Set up exception handlers for tracing and breakpoints diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c --- v2.3.42/linux/arch/ppc/kernel/ppc_htab.c Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/kernel/ppc_htab.c Wed Feb 9 19:43:47 2000 @@ -45,17 +45,9 @@ extern unsigned long pte_errors; static struct file_operations ppc_htab_operations = { - ppc_htab_lseek, /* lseek */ - ppc_htab_read, /* read */ - ppc_htab_write, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* can't fsync */ + llseek: ppc_htab_lseek, + read: ppc_htab_read, + write: ppc_htab_write, }; /* @@ -531,7 +523,8 @@ "0.5", "1.0", "(reserved2)", "(reserved3)" }; - if ( (_get_PVR() >> 16) != 8) return -EFAULT; + if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12)) + return -EFAULT; if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) { *lenp = 0; diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.3.42/linux/arch/ppc/kernel/ppc_ksyms.c Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/kernel/ppc_ksyms.c Wed Feb 9 19:43:47 2000 @@ -229,6 +229,8 @@ EXPORT_SYMBOL(find_phandle); EXPORT_SYMBOL(device_is_compatible); EXPORT_SYMBOL(machine_is_compatible); +EXPORT_SYMBOL(find_pci_device_OFnode); +EXPORT_SYMBOL(find_all_nodes); EXPORT_SYMBOL(get_property); EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- v2.3.42/linux/arch/ppc/kernel/prep_pci.c Thu Jan 6 12:57:47 2000 +++ linux/arch/ppc/kernel/prep_pci.c Wed Feb 9 19:43:47 2000 @@ -40,7 +40,7 @@ static unsigned long *ProcInfo; extern int chrp_get_irq(struct pt_regs *); -extern void chrp_post_irq(int); +extern void chrp_post_irq(struct pt_regs* regs, int); /* Tables for known hardware */ diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.3.42/linux/arch/ppc/kernel/process.c Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/kernel/process.c Wed Feb 9 19:43:47 2000 @@ -57,6 +57,8 @@ }; /* only used to get secondary processor up */ struct task_struct *current_set[NR_CPUS] = {&init_task, }; +char *sysmap = NULL; +unsigned long sysmap_size = 0; #undef SHOW_TASK_SWITCHES 1 #undef CHECK_STACK 1 diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.3.42/linux/arch/ppc/kernel/prom.c Tue Dec 7 09:32:42 1999 +++ linux/arch/ppc/kernel/prom.c Wed Feb 9 19:43:47 2000 @@ -30,6 +30,10 @@ #include #include +#ifdef CONFIG_FB +#include +#endif + /* * Properties whose value is longer than this get excluded from our * copy of the device tree. This way we don't waste space storing @@ -91,7 +95,7 @@ char *of_stdout_device = 0; prom_entry prom = 0; -ihandle prom_chosen = 0, prom_stdout = 0; +ihandle prom_chosen = 0, prom_stdout = 0, prom_disp_node = 0; extern char *klimit; char *bootpath = 0; @@ -102,33 +106,35 @@ unsigned int rtas_size = 0; unsigned int old_rtas = 0; +int use_of_interrupt_tree = 0; static struct device_node *allnodes = 0; +#ifdef CONFIG_BOOTX_TEXT + static void clearscreen(void); static void flushscreen(void); -#ifdef CONFIG_BOOTX_TEXT - void drawchar(char c); void drawstring(const char *c); static void drawhex(unsigned long v); static void scrollscreen(void); static void draw_byte(unsigned char c, long locX, long locY); -static void draw_byte_32(unsigned char *bits, unsigned long *base); -static void draw_byte_16(unsigned char *bits, unsigned long *base); -static void draw_byte_8(unsigned char *bits, unsigned long *base); - -static long g_loc_X; -static long g_loc_Y; -static long g_max_loc_X; -static long g_max_loc_Y; +static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb); +static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb); +static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb); + +/* We want those in data, not BSS */ +static long g_loc_X = 0; +static long g_loc_Y = 0; +static long g_max_loc_X = 0; +static long g_max_loc_Y = 0; #define cmapsz (16*256) static unsigned char vga_font[cmapsz]; -#endif +#endif /* CONFIG_BOOTX_TEXT */ static void *call_prom(const char *service, int nargs, int nret, ...); @@ -138,15 +144,25 @@ unsigned long, struct device_node ***); static unsigned long finish_node(struct device_node *, unsigned long, interpret_func *); +static unsigned long finish_node_interrupts(struct device_node *, unsigned long); static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); static void *early_get_property(unsigned long, unsigned long, char *); +#ifdef CONFIG_BOOTX_TEXT +static void setup_disp_fake_bi(ihandle dp); +static void prom_welcome(boot_infos_t* bi, unsigned long phys); +#endif + extern void enter_rtas(void *); extern unsigned long reloc_offset(void); extern char cmd_line[512]; /* XXX */ boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */ +#ifdef CONFIG_BOOTX_TEXT +boot_infos_t *disp_bi = 0; +boot_infos_t fake_bi = {0,}; +#endif unsigned long dev_tree_size; /* @@ -240,7 +256,7 @@ if (RELOC(prom_stdout) == 0) { #ifdef CONFIG_BOOTX_TEXT - if (RELOC(boot_infos) != 0) + if (RELOC(disp_bi) != 0) drawstring(msg); #endif return; @@ -261,7 +277,6 @@ } } -unsigned long smp_ibm_chrp_hack __initdata = 0; unsigned long smp_chrp_cpu_nr __initdata = 1; /* @@ -269,23 +284,29 @@ * handling exceptions and the MMU hash table for us. */ __init -void +unsigned long prom_init(int r3, int r4, prom_entry pp) { #ifdef CONFIG_SMP int i; phandle node; char type[16], *path; -#endif +#endif + int chrp = 0; unsigned long mem; - ihandle prom_rtas; + ihandle prom_rtas, prom_mmu, prom_op; unsigned long offset = reloc_offset(); int l; char *p, *d; + int prom_version = 0; + unsigned long phys; + + /* Default */ + phys = offset + KERNELBASE; /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) - return; + return phys; /* If we came here from BootX, clear the screen, * set up some pointers and return. */ @@ -294,22 +315,20 @@ unsigned long space; unsigned long ptr, x; char *model; -#ifdef CONFIG_BOOTX_TEXT - unsigned long flags; -#endif RELOC(boot_infos) = PTRUNRELOC(bi); if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) bi->logicalDisplayBase = 0; - clearscreen(); - #ifdef CONFIG_BOOTX_TEXT RELOC(g_loc_X) = 0; RELOC(g_loc_Y) = 0; RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; + RELOC(disp_bi) = PTRUNRELOC(bi); + clearscreen(); + /* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since there is nothing much we can do with an incompatible version, except display a message and eventually hang the processor... @@ -320,23 +339,9 @@ if (!BOOT_INFO_IS_COMPATIBLE(bi)) prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n")); - prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); - prom_print(RELOC("\nstarted at : 0x")); - drawhex(reloc_offset() + KERNELBASE); - prom_print(RELOC("\nlinked at : 0x")); - drawhex(KERNELBASE); - prom_print(RELOC("\nframe buffer at : 0x")); - drawhex((unsigned long)bi->dispDeviceBase); - prom_print(RELOC(" (phys), 0x")); - drawhex((unsigned long)bi->logicalDisplayBase); - prom_print(RELOC(" (log)")); - prom_print(RELOC("\nMSR : 0x")); - __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); - drawhex(flags); - prom_print(RELOC("\n\n")); -#endif - /* Out of the #if/#endif since it flushes the clearscreen too */ + prom_welcome(bi, phys); flushscreen(); +#endif /* CONFIG_BOOTX_TEXT */ /* New BootX enters kernel with MMU off, i/os are not allowed here. This hack will have been done by the boostrap anyway. @@ -381,12 +386,12 @@ prom_print(RELOC("booting...\n")); flushscreen(); #endif - return; + return phys; } /* check if we're prep, return if we are */ if ( *(unsigned long *)(0) == 0xdeadc0de ) - return; + return phys; /* First get a handle for the stdout device */ RELOC(prom) = pp; @@ -407,6 +412,30 @@ RELOC(of_stdout_device) = PTRUNRELOC(p); mem += strlen(p) + 1; + /* Find the OF version */ + prom_op = call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom")); + prom_version = 0; + if (prom_op != (void*)-1) { + char model[64]; + int sz; + sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op, RELOC("model"), model, 64); + if (sz > 0) { + char *c; + /* hack to skip the ibm chrp firmware # */ + if ( strncmp(model,RELOC("IBM"),3) ) { + for (c = model; *c; c++) + if (*c >= '0' && *c <= '9') { + prom_version = *c - '0'; + break; + } + } + else + chrp = 1; + } + } + if (prom_version >= 3) + prom_print(RELOC("OF Version 3 detected.\n")); + /* Get the boot device and translate it to a full OF pathname. */ p = (char *) mem; l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), @@ -478,6 +507,42 @@ prom_print(RELOC(" done\n")); } + /* If we are already running at 0xc0000000, we assume we were loaded by + * an OF bootloader which did set a BAT for us. This breaks OF translate + * so we force phys to be 0 + */ + if (offset == 0) + phys = 0; + else { + if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), + RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) { + prom_print(RELOC(" no MMU found\n")); + } else { + int nargs; + struct prom_args prom_args; + nargs = 4; + prom_args.service = RELOC("call-method"); + prom_args.nargs = nargs; + prom_args.nret = 4; + prom_args.args[0] = RELOC("translate"); + prom_args.args[1] = prom_mmu; + prom_args.args[2] = (void *)(offset + KERNELBASE); + prom_args.args[3] = (void *)1; + RELOC(prom)(&prom_args); + + /* We assume the phys. address size is 3 cells */ + if (prom_args.args[nargs] != 0) + prom_print(RELOC(" (translate failed) ")); + else + phys = (unsigned long)prom_args.args[nargs+3]; + } + } + +#ifdef CONFIG_BOOTX_TEXT + if (!chrp && RELOC(prom_disp_node) != 0) + setup_disp_fake_bi(RELOC(prom_disp_node)); +#endif + #ifdef CONFIG_SMP /* * With CHRP SMP we need to use the OF to start the other @@ -512,7 +577,7 @@ node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); if ( (int)call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),type, sizeof(type)) <= 0) - return; + return phys; /* copy the holding pattern code to someplace safe (8M) */ memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x100 ); @@ -554,6 +619,79 @@ prom_print(RELOC("...failed\n")); } #endif + /* If OpenFirmware version >= 3, then use quiesce call */ + if (prom_version >= 3) { + prom_print(RELOC("Calling quiesce ...\n")); + call_prom(RELOC("quiesce"), 0, 0); + offset = reloc_offset(); + phys = offset + KERNELBASE; + } + +#ifdef CONFIG_BOOTX_TEXT + if (!chrp && RELOC(disp_bi)) { + RELOC(prom_stdout) = 0; + clearscreen(); + prom_welcome(PTRRELOC(RELOC(disp_bi)), phys); + prom_print(RELOC("booting...\n")); + } +#endif + + return phys; +} + +#ifdef CONFIG_BOOTX_TEXT +__init static void +prom_welcome(boot_infos_t* bi, unsigned long phys) +{ + unsigned long offset = reloc_offset(); + unsigned long flags; + unsigned long pvr; + + prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); + prom_print(RELOC("\nstarted at : 0x")); + drawhex(phys); + prom_print(RELOC("\nlinked at : 0x")); + drawhex(KERNELBASE); + prom_print(RELOC("\nframe buffer at : 0x")); + drawhex((unsigned long)bi->dispDeviceBase); + prom_print(RELOC(" (phys), 0x")); + drawhex((unsigned long)bi->logicalDisplayBase); + prom_print(RELOC(" (log)")); + prom_print(RELOC("\nMSR : 0x")); + __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); + drawhex(flags); + __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); + pvr >>= 16; + if (pvr > 1) { + prom_print(RELOC("\nHID0 : 0x")); + __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); + drawhex(flags); + } + if (pvr == 8 || pvr == 12) { + prom_print(RELOC("\nICTC : 0x")); + __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); + drawhex(flags); + } + prom_print(RELOC("\n\n")); +} +#endif + +static int prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + struct prom_args prom_args; + unsigned long offset = reloc_offset(); + + prom_args.service = RELOC("call-method"); + prom_args.nargs = 6; + prom_args.nret = 1; + prom_args.args[0] = RELOC("color!"); + prom_args.args[1] = ih; + prom_args.args[2] = (void *) i; + prom_args.args[3] = (void *) b; + prom_args.args[4] = (void *) g; + prom_args.args[5] = (void *) r; + RELOC(prom)(&prom_args); + return (int) prom_args.args[6]; } /* @@ -573,6 +711,26 @@ int i; unsigned long offset = reloc_offset(); char type[16], *path; + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + + RELOC(prom_disp_node) = 0; for (node = 0; prom_next_node(&node); ) { type[0] = 0; @@ -595,6 +753,26 @@ } prom_print(RELOC("... ok\n")); + if (RELOC(prom_disp_node) == 0) + RELOC(prom_disp_node) = node; + + /* Setup a useable color table when the appropriate + * method is available. Should update this to set-colors */ + for (i = 0; i < 32; i++) + if (prom_set_color(ih, i, RELOC(default_colors)[i*3], + RELOC(default_colors)[i*3+1], + RELOC(default_colors)[i*3+2]) != 0) + break; + +#ifdef CONFIG_FB + for (i = 0; i < LINUX_LOGO_COLORS; i++) + if (prom_set_color(ih, i + 32, + RELOC(linux_logo_red)[i], + RELOC(linux_logo_green)[i], + RELOC(linux_logo_blue)[i]) != 0) + break; +#endif /* CONFIG_FB */ + /* * If this display is the device that OF is using for stdout, * move it to the front of the list. @@ -614,6 +792,79 @@ return ALIGN(mem); } +/* This function will enable the early boot text when doing OF booting. This + * way, xmon output should work too + */ +#ifdef CONFIG_BOOTX_TEXT +__init +static void +setup_disp_fake_bi(ihandle dp) +{ + unsigned int len; + int width = 640, height = 480, depth = 8, pitch; + unsigned address; + boot_infos_t* bi; + unsigned long offset = reloc_offset(); + + prom_print(RELOC("Initing fake screen\n")); + + len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len)); + if (len == 0) + prom_print(RELOC("Warning: assuming display depth = 8\n")); + else + depth = len; + width = len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len)); + width = len; + if (width == 0) { + prom_print(RELOC("Failed to get width\n")); + return; + } + height = len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len)); + height = len; + if (height == 0) { + prom_print(RELOC("Failed to get height\n")); + return; + } + pitch = len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len)); + pitch = len; + if (pitch == 0) { + prom_print(RELOC("Failed to get pitch\n")); + return; + } + address = len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len)); + address = len; + if (address == 0) { + prom_print(RELOC("Failed to get address\n")); + return; + } +#if 0 + /* kludge for valkyrie */ + if (strcmp(dp->name, "valkyrie") == 0) + address += 0x1000; + } +#endif + + RELOC(disp_bi) = &fake_bi; + bi = PTRRELOC((&fake_bi)); + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y) = 0; + RELOC(g_max_loc_X) = width / 8; + RELOC(g_max_loc_Y) = height / 16; + bi->logicalDisplayBase = (unsigned char *)address; + bi->dispDeviceBase = (unsigned char *)address; + bi->dispDeviceRowBytes = pitch; + bi->dispDeviceDepth = depth; + bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; + bi->dispDeviceRect[2] = width; + bi->dispDeviceRect[3] = height; +} +#endif + __init static int prom_next_node(phandle *nodep) @@ -748,6 +999,16 @@ finish_device_tree(void) { unsigned long mem = (unsigned long) klimit; + char* model; + + /* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not. + * This code was only tested with Core99 machines so far, but should be easily + * adapted to older newworld machines (iMac, B&W G3, Lombard). + */ + model = get_property(allnodes, "model", 0); + if ((boot_infos == 0) && model && (strcmp(model, "PowerBook2,1") == 0 + || strcmp(model, "PowerMac2,1") == 0 || strcmp(model, "PowerMac3,1") == 0)) + use_of_interrupt_tree = 1; mem = finish_node(allnodes, mem, NULL); dev_tree_size = mem - (unsigned long) allnodes; @@ -788,6 +1049,9 @@ if (ifunc != NULL) { mem_start = ifunc(np, mem_start); } + if (use_of_interrupt_tree) { + mem_start = finish_node_interrupts(np, mem_start); + } /* the f50 sets the name to 'display' and 'compatible' to what we * expect for the name -- Cort @@ -834,6 +1098,133 @@ 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. + */ +__init +static unsigned long +finish_node_interrupts(struct device_node *np, unsigned long mem_start) +{ + /* 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; + + reg = (unsigned int *)get_property(np, "reg", &l); + regpsize = l>>2; + + /* 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; + 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++; + np->intrs[i].sense = 0; + if (isize > 1) + np->intrs[i].sense = *interrupts++; + for (j=2; j>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=regpsize) || ((mask & *map) != (mask & reg[i]))) + found = 0; + map++; + map_size--; + } + for (i=0; iparent; + } while(node); + + 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 @@ -892,6 +1283,9 @@ mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + /* * If the pci host bridge has an interrupt-map property, * look for our node in it. @@ -901,14 +1295,28 @@ 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 -= sizeof(struct pci_intr_map)) >= 0; ++i) { - if (imp[i].addr.a_hi == devfn) { - np->intrs[np->n_intrs].line = imp[i].intr; - np->intrs[np->n_intrs].sense = 0; + 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 = 0; /* FIXME */ ++np->n_intrs; } + imp = (struct pci_intr_map *)(((unsigned int)imp) + + cell_size); } if (np->n_intrs == 0) np->intrs = 0; @@ -965,6 +1373,9 @@ mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); @@ -988,13 +1399,14 @@ struct reg_property *rp; struct address_range *adr; unsigned long base_address; - int i, l, *ip; + int i, l, keylargo, *ip; struct device_node *db; base_address = 0; for (db = np->parent; db != NULL; db = db->parent) { if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { base_address = db->addrs[0].address; + keylargo = device_is_compatible(db, "Keylargo"); break; } } @@ -1014,6 +1426,9 @@ mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + ip = (int *) get_property(np, "interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "AAPL,interrupts", &l); @@ -1022,9 +1437,15 @@ 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++; - np->intrs[i].sense = 0; + if (keylargo) + np->intrs[i].sense = *ip++; + else + np->intrs[i].sense = 0; } } else { /* CHRP machines */ @@ -1064,6 +1485,9 @@ mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; @@ -1101,6 +1525,9 @@ mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); @@ -1157,6 +1584,49 @@ return head; } +/* Finds a device node given its PCI bus number, device number + * and function number + */ +__openfirmware +struct device_node * +find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn) +{ + struct device_node* np; + unsigned int *reg; + int l; + + for (np = allnodes; np != 0; np = np->allnext) { + char *pname = np->parent ? + (char *)get_property(np->parent, "name", &l) : 0; + if (pname && strcmp(pname, "mac-io") == 0) + continue; + reg = (unsigned int *) get_property(np, "reg", &l); + if (reg == 0 || l < sizeof(struct reg_property)) + continue; + if (((reg[0] >> 8) & 0xff) == dev_fn && ((reg[0] >> 16) & 0xff) == bus) + break; + } + return np; +} + +/* + * Returns all nodes linked together + */ +__openfirmware +struct device_node * +find_all_nodes(void) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + *prevp = np; + prevp = &np->next; + } + *prevp = 0; + return head; +} + /* Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */ @@ -1377,18 +1847,28 @@ prom_exit(); } -#ifdef CONFIG_XMON +#ifdef CONFIG_BOOTX_TEXT + +/* Here's a small text engine to use during early boot or for debugging purposes + * + * todo: + * + * - build some kind of vgacon with it to enable early printk + * - move to a separate file + * - add a few video driver hooks to keep in sync with display + * changes. + */ + __init void map_bootx_text(void) { - if (boot_infos == 0) + if (disp_bi == 0) return; - boot_infos->logicalDisplayBase = - ioremap((unsigned long) boot_infos->dispDeviceBase, - boot_infos->dispDeviceRowBytes * boot_infos->dispDeviceRect[3]); + disp_bi->logicalDisplayBase = + ioremap((unsigned long) disp_bi->dispDeviceBase, + disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]); } -#endif /* CONFIG_XMON */ /* Calc the base address of a given point (x,y) */ __pmac @@ -1410,7 +1890,7 @@ clearscreen(void) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; @@ -1435,7 +1915,7 @@ flushscreen(void) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; @@ -1452,14 +1932,12 @@ } } -#ifdef CONFIG_BOOTX_TEXT - __pmac static void scrollscreen(void) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned long *src = (unsigned long *)calc_base(bi,0,16); unsigned long *dst = (unsigned long *)calc_base(bi,0,0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * @@ -1563,19 +2041,20 @@ draw_byte(unsigned char c, long locX, long locY) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned char *base = calc_base(bi, locX << 3, locY << 4); unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; + int rb = bi->dispDeviceRowBytes; switch(bi->dispDeviceDepth) { case 32: - draw_byte_32(font, (unsigned long *)base); + draw_byte_32(font, (unsigned long *)base, rb); break; case 16: - draw_byte_16(font, (unsigned long *)base); + draw_byte_16(font, (unsigned long *)base, rb); break; case 8: - draw_byte_8(font, (unsigned long *)base); + draw_byte_8(font, (unsigned long *)base, rb); break; default: break; @@ -1613,15 +2092,12 @@ __pmac static void -draw_byte_32(unsigned char *font, unsigned long *base) +draw_byte_32(unsigned char *font, unsigned long *base, int rb) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); int l, bits; int fg = 0xFFFFFFFFUL; int bg = 0x00000000UL; - for (l = 0; l < 16; ++l) { bits = *font++; @@ -1633,19 +2109,18 @@ base[5] = (-((bits >> 2) & 1) & fg) ^ bg; base[6] = (-((bits >> 1) & 1) & fg) ^ bg; base[7] = (-(bits & 1) & fg) ^ bg; - base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + base = (unsigned long *) ((char *)base + rb); } } __pmac static void -draw_byte_16(unsigned char *font, unsigned long *base) +draw_byte_16(unsigned char *font, unsigned long *base, int rb) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); int l, bits; int fg = 0xFFFFFFFFUL; int bg = 0x00000000UL; + unsigned long offset = reloc_offset(); unsigned long *eb = RELOC(expand_bits_16); for (l = 0; l < 16; ++l) @@ -1655,19 +2130,18 @@ base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; base[3] = (eb[bits & 3] & fg) ^ bg; - base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + base = (unsigned long *) ((char *)base + rb); } } __pmac static void -draw_byte_8(unsigned char *font, unsigned long *base) +draw_byte_8(unsigned char *font, unsigned long *base, int rb) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); int l, bits; int fg = 0x0F0F0F0FUL; int bg = 0x00000000UL; + unsigned long offset = reloc_offset(); unsigned long *eb = RELOC(expand_bits_8); for (l = 0; l < 16; ++l) @@ -1675,7 +2149,7 @@ bits = *font++; base[0] = (eb[bits >> 4] & fg) ^ bg; base[1] = (eb[bits & 0xf] & fg) ^ bg; - base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + base = (unsigned long *) ((char *)base + rb); } } @@ -2026,3 +2500,4 @@ }; #endif /* CONFIG_BOOTX_TEXT */ + diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/semaphore.c linux/arch/ppc/kernel/semaphore.c --- v2.3.42/linux/arch/ppc/kernel/semaphore.c Tue Aug 31 17:29:13 1999 +++ linux/arch/ppc/kernel/semaphore.c Wed Feb 9 19:43:47 2000 @@ -137,3 +137,44 @@ { return waking_non_zero_trylock(sem); } + + +/* + * rw semaphores Ani Joshi + * based on alpha port by Andrea Arcangeli + */ + +void down_read_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue_exclusive(&sem->wait, &wait); + + do { + __set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + spin_unlock_irq(&sem->lock); + schedule(); + spin_lock_irq(&sem->lock); + } while(sem->wr); + + remove_wait_queue(&sem->wait, &wait); +} + +void down_write_failed(struct rw_semaphore *sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + + add_wait_queue_exclusive(&sem->wait, &wait); + + do { + __set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + spin_unlock_irq(&sem->lock); + schedule(); + spin_lock_irq(&sem->lock); + } while(sem->rd || sem->wr); + + remove_wait_queue(&sem->wait, &wait); +} + diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.42/linux/arch/ppc/kernel/setup.c Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/kernel/setup.c Wed Feb 9 19:43:47 2000 @@ -69,6 +69,13 @@ unsigned long r6, unsigned long r7); +#ifdef CONFIG_BOOTX_TEXT +extern void map_bootx_text(void); +#endif +#ifdef CONFIG_XMON +extern void xmon_map_scc(void); +#endif + extern boot_infos_t *boot_infos; char saved_command_line[256]; unsigned char aux_device_present; @@ -261,7 +268,7 @@ } break; case 0x000C: - len += sprintf(len+buffer, "7400\n"); + len += sprintf(len+buffer, "7400 (G4)\n"); break; case 0x0020: len += sprintf(len+buffer, "403G"); @@ -292,7 +299,7 @@ * Assume here that all clock rates are the same in a * smp system. -- Cort */ -#ifndef CONFIG_8xx +#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) if ( have_of ) { struct device_node *cpu_node; @@ -316,7 +323,7 @@ len += sprintf(len+buffer, "clock\t\t: %dMHz\n", *fp / 1000000); } -#endif +#endif /* !CONFIG_4xx && !CONFIG_8xx */ if (ppc_md.setup_residual != NULL) { @@ -410,8 +417,9 @@ unsigned long r6, unsigned long r7) { parse_bootinfo(); - + if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100); + #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) #ifndef CONFIG_MACH_SPECIFIC /* if we didn't get any bootinfo telling us what we are... */ @@ -477,11 +485,12 @@ char *p; #ifdef CONFIG_BLK_DEV_INITRD - if (r3 - KERNELBASE < 0x800000 - && r4 != 0 && r4 != 0xdeadbeef) { + if (r3 && r4 && r4 != 0xdeadbeef) + { initrd_start = r3; initrd_end = r3 + r4; ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + initrd_below_start_ok = 1; } #endif cmd_line[0] = 0; @@ -519,6 +528,7 @@ default: printk("Unknown machine type in identify_machine!\n"); } + /* Check for nobats option (used in mapin_ram). */ if (strstr(cmd_line, "nobats")) { extern int __map_without_bats; @@ -567,9 +577,11 @@ int parse_bootinfo(void) { struct bi_record *rec; - extern char _end[]; + extern char __bss_start[]; + extern char *sysmap; + extern unsigned long sysmap_size; - rec = (struct bi_record *)PAGE_ALIGN((ulong)_end); + rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20)); if ( rec->tag != BI_FIRST ) { /* @@ -577,11 +589,10 @@ * we have the bootloader handle all the relocation and * prom calls -- Cort */ - rec = (struct bi_record *)PAGE_ALIGN((ulong)_end+0x10000); + rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20)); if ( rec->tag != BI_FIRST ) return -1; } - for ( ; rec->tag != BI_LAST ; rec = (struct bi_record *)((ulong)rec + rec->size) ) { @@ -591,6 +602,11 @@ case BI_CMD_LINE: memcpy(cmd_line, (void *)data, rec->size); break; + case BI_SYSMAP: + sysmap = (char *)((data[0] >= (KERNELBASE)) ? data[0] : + (data[0]+KERNELBASE)); + sysmap_size = data[1]; + break; #ifdef CONFIG_BLK_DEV_INITRD case BI_INITRD: initrd_start = data[0]; @@ -603,7 +619,6 @@ have_of = data[1]; break; #endif /* CONFIG_MACH_SPECIFIC */ - } } @@ -613,7 +628,7 @@ /* Checks "l2cr=xxxx" command-line option */ void ppc_setup_l2cr(char *str, int *ints) { - if ( (_get_PVR() >> 16) == 8) + if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) ) { unsigned long val = simple_strtoul(str, NULL, 0); printk(KERN_INFO "l2cr set to %lx\n", val); @@ -639,12 +654,21 @@ extern char *klimit; extern void do_init_bootmem(void); +#ifdef CONFIG_BOOTX_TEXT + map_bootx_text(); + prom_print("identify machine\n"); +#endif + #ifdef CONFIG_XMON - extern void xmon_map_scc(void); xmon_map_scc(); if (strstr(cmd_line, "xmon")) xmon(0); #endif /* CONFIG_XMON */ + if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); +#if defined(CONFIG_KGDB) + set_debug_traps(); + breakpoint(); +#endif /* reboot on panic */ panic_timeout = 180; @@ -653,16 +677,16 @@ init_mm.end_code = (unsigned long) _etext; init_mm.end_data = (unsigned long) _edata; init_mm.brk = (unsigned long) klimit; - + /* Save unparsed command line copy for /proc/cmdline */ strcpy(saved_command_line, cmd_line); *cmdline_p = cmd_line; /* set up the bootmem stuff with available memory */ do_init_bootmem(); + if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); ppc_md.setup_arch(); - /* clear the progress line */ if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); } diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/sleep.S linux/arch/ppc/kernel/sleep.S --- v2.3.42/linux/arch/ppc/kernel/sleep.S Sat Oct 9 11:47:50 1999 +++ linux/arch/ppc/kernel/sleep.S Wed Feb 9 19:43:47 2000 @@ -171,6 +171,11 @@ */ wake_up: + /* Flash inval the instruction cache */ + mfspr r3,HID0 + ori r3,r3, HID0_ICFI + mtspr HID0,r3 + isync /* Restore the HID0 register. This turns on the L1 caches. */ subi r1,r1,SL_PC lwz r3,SL_HID0(r1) diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c --- v2.3.42/linux/arch/ppc/kernel/syscalls.c Fri Sep 10 23:57:28 1999 +++ linux/arch/ppc/kernel/syscalls.c Wed Feb 9 19:43:47 2000 @@ -252,9 +252,14 @@ asmlinkage int sys_uname(struct old_utsname * name) { - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) - return 0; - return -EFAULT; + int err; + + if (!name) + return -EFAULT; + down_read(&uts_sem); + err = copy_to_user(name, &system_utsname, sizeof (*name)); + up(&uts_sem); + return err ? -EFAULT : 0; } asmlinkage int sys_olduname(struct oldold_utsname * name) @@ -266,6 +271,7 @@ if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) return -EFAULT; + down_read(&uts_sem); error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); error -= __put_user(0,name->sysname+__OLD_UTS_LEN); error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); @@ -277,6 +283,7 @@ error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); error = __put_user(0,name->machine+__OLD_UTS_LEN); error = error ? -EFAULT : 0; + up(&uts_sem); return error; } diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.3.42/linux/arch/ppc/kernel/traps.c Tue Jan 11 22:31:38 2000 +++ linux/arch/ppc/kernel/traps.c Wed Feb 9 19:43:47 2000 @@ -128,6 +128,20 @@ _exception(SIGSEGV, regs); } +void +SMIException(struct pt_regs *regs) +{ +#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) + { + debugger(regs); + return; + } +#endif + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("System Management Interrupt"); +} + #if defined(CONFIG_ALTIVEC) void AltiVecUnavailable(struct pt_regs *regs) diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/walnut_setup.c linux/arch/ppc/kernel/walnut_setup.c --- v2.3.42/linux/arch/ppc/kernel/walnut_setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/walnut_setup.c Thu Feb 10 12:37:51 2000 @@ -0,0 +1,295 @@ +/* + * + * Copyright (c) 1999-2000 Grant Erickson + * + * Module name: walnut_setup.c + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM PowerPC 403GP "Walnut" evaluation board. Adapted from original + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "local_irq.h" +#include "ppc4xx_pic.h" +#include "time.h" +#include "walnut_setup.h" + + +/* Function Prototypes */ + +extern void abort(void); + +/* Global Variables */ + +unsigned char __res[sizeof(bd_t)]; + + +/* + * void __init walnut_init() + * + * Description: + * This routine... + * + * Input(s): + * r3 - Optional pointer to a board information structure. + * r4 - Optional pointer to the physical starting address of the init RAM + * disk. + * r5 - Optional pointer to the physical ending address of the init RAM + * disk. + * r6 - Optional pointer to the physical starting address of any kernel + * command-line parameters. + * r7 - Optional pointer to the physical ending address of any kernel + * command-line parameters. + * + * Output(s): + * N/A + * + * Returns: + * N/A + * + */ +void __init +walnut_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + /* + * If we were passed in a board information, copy it into the + * residual data area. + */ + if (r3) { + memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t)); + } + +#if defined(CONFIG_BLK_DEV_INITRD) + /* + * If the init RAM disk has been configured in, and there's a valid + * starting address for it, set it up. + */ + if (r4) { + initrd_start = r4 + KERNELBASE; + initrd_end = r5 + KERNELBASE; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + /* Copy the kernel command line arguments to a safe place. */ + + if (r6) { + *(char *)(r7 + KERNELBASE) = 0; + strcpy(cmd_line, (char *)(r6 + KERNELBASE)); + } + + /* Initialize machine-dependency vectors */ + + ppc_md.setup_arch = walnut_setup_arch; + ppc_md.setup_residual = walnut_setup_residual; + ppc_md.get_cpuinfo = NULL; + ppc_md.irq_cannonicalize = NULL; + ppc_md.init_IRQ = walnut_init_IRQ; + ppc_md.get_irq = walnut_get_irq; + ppc_md.init = NULL; + + ppc_md.restart = walnut_restart; + ppc_md.power_off = walnut_power_off; + ppc_md.halt = walnut_halt; + + ppc_md.time_init = walnut_time_init; + ppc_md.set_rtc_time = walnut_set_rtc_time; + ppc_md.get_rtc_time = walnut_get_rtc_time; + ppc_md.calibrate_decr = walnut_calibrate_decr; + + ppc_md.kbd_setkeycode = NULL; + ppc_md.kbd_getkeycode = NULL; + ppc_md.kbd_translate = NULL; + ppc_md.kbd_unexpected_up = NULL; + ppc_md.kbd_leds = NULL; + ppc_md.kbd_init_hw = NULL; + +#if defined(CONFIG_MAGIC_SYSRQ) + ppc_md.ppc_kbd_sysrq_xlate = NULL; +#endif + + return; +} + +/* + * Document me. + */ +void __init +walnut_setup_arch(void) +{ + /* XXX - Implement me */ +} + +/* + * int walnut_setup_residual() + * + * Description: + * This routine pretty-prints the platform's internal CPU and bus clock + * frequencies into the buffer for usage in /proc/cpuinfo. + * + * Input(s): + * *buffer - Buffer into which CPU and bus clock frequencies are to be + * printed. + * + * Output(s): + * *buffer - Buffer with the CPU and bus clock frequencies. + * + * Returns: + * The number of bytes copied into 'buffer' if OK, otherwise zero or less + * on error. + */ +int +walnut_setup_residual(char *buffer) +{ + int len = 0; + bd_t *bp = (bd_t *)__res; + + len += sprintf(len + buffer, + "clock\t\t: %dMHz\n" + "bus clock\t\t: %dMHz\n", + bp->bi_intfreq / 1000000, + bp->bi_busfreq / 1000000); + + return (len); +} + +/* + * Document me. + */ +void __init +walnut_init_IRQ(void) +{ + int i; + + ppc4xx_pic_init(); + + for (i = 0; i < NR_IRQS; i++) { + irq_desc[i].handler = ppc4xx_pic; + } + + return; +} + +/* + * Document me. + */ +int +walnut_get_irq(struct pt_regs *regs) +{ + return (ppc4xx_pic_get_irq(regs)); +} + +/* + * Document me. + */ +void +walnut_restart(char *cmd) +{ + abort(); +} + +/* + * Document me. + */ +void +walnut_power_off(void) +{ + walnut_restart(NULL); +} + +/* + * Document me. + */ +void +walnut_halt(void) +{ + walnut_restart(NULL); +} + +/* + * Document me. + */ +void __init +walnut_time_init(void) +{ + /* XXX - Implement me */ +} + +/* + * Document me. + */ +int __init +walnut_set_rtc_time(unsigned long time) +{ + /* XXX - Implement me */ + + return (0); +} + +/* + * Document me. + */ +unsigned long __init +walnut_get_rtc_time(void) +{ + /* XXX - Implement me */ + + return (0); +} + +/* + * void __init walnut_calibrate_decr() + * + * Description: + * This routine retrieves the internal processor frequency from the board + * information structure, sets up the kernel timer decrementer based on + * that value, enables the 403 programmable interval timer (PIT) and sets + * it up for auto-reload. + * + * Input(s): + * N/A + * + * Output(s): + * N/A + * + * Returns: + * N/A + * + */ +void __init +walnut_calibrate_decr(void) +{ + unsigned int freq; + bd_t *bip = (bd_t *)__res; + + freq = bip->bi_intfreq; + + decrementer_count = freq / HZ; + count_period_num = 1; + count_period_den = freq; + + /* Enable the PIT and set auto-reload of its value */ + + mtspr(SPRN_TCR, TCR_PIE | TCR_ARE); + + /* Clear any pending timer interrupts */ + + mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS); +} diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/walnut_setup.h linux/arch/ppc/kernel/walnut_setup.h --- v2.3.42/linux/arch/ppc/kernel/walnut_setup.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/walnut_setup.h Thu Feb 10 12:37:51 2000 @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 1999-2000 Grant Erickson + * + * Module name: walnut_setup.c + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM PowerPC 405GP "Walnut" evaluation board. Adapted from original + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + */ + +#ifndef __WALNUT_SETUP_H__ +#define __WALNUT_SETUP_H__ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned char __res[sizeof(bd_t)]; + +extern void walnut_init(unsigned long r3, + unsigned long ird_start, + unsigned long ird_end, + unsigned long cline_start, + unsigned long cline_end); +extern void walnut_setup_arch(void); +extern int walnut_setup_residual(char *buffer); +extern void walnut_init_IRQ(void); +extern int walnut_get_irq(struct pt_regs *regs); +extern void walnut_restart(char *cmd); +extern void walnut_power_off(void); +extern void walnut_halt(void); +extern void walnut_time_init(void); +extern int walnut_set_rtc_time(unsigned long now); +extern unsigned long walnut_get_rtc_time(void); +extern void walnut_calibrate_decr(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __WALNUT_SETUP_H__ */ diff -u --recursive --new-file v2.3.42/linux/arch/ppc/mm/4xx_tlb.c linux/arch/ppc/mm/4xx_tlb.c --- v2.3.42/linux/arch/ppc/mm/4xx_tlb.c Tue Jan 11 22:31:38 2000 +++ linux/arch/ppc/mm/4xx_tlb.c Wed Feb 9 19:43:47 2000 @@ -1,6 +1,9 @@ /* * - * Copyright (c) 1999 Grant Erickson + * Copyright (c) 1998-1999 TiVo, Inc. + * Original implementation. + * Copyright (c) 1999-2000 Grant Erickson + * Minor rework. * * Module name: 4xx_tlb.c * @@ -9,7 +12,10 @@ * */ +#include + #include +#include #include #include #include @@ -26,372 +32,327 @@ #endif -/* Function Macros */ - - -/* Type Definitios */ - -typedef struct pin_entry_s { - unsigned int e_pinned: 1, /* This TLB entry is pinned down. */ - e_used: 23; /* Number of users for this mapping. */ -} pin_entry_t; - - /* Global Variables */ -static pin_entry_t pin_table[PPC4XX_TLB_SIZE]; +static int pinned = 0; /* Function Prototypes */ +static int PPC4xx_tlb_miss(struct pt_regs *, unsigned long, int); -void -PPC4xx_tlb_pin(unsigned long va, unsigned long pa, int pagesz, int cache) -{ - int i, found = FALSE; - unsigned long tag, data; - unsigned long opid; - - opid = mfspr(SPRN_PID); - mtspr(SPRN_PID, 0); - - data = (pa & TLB_RPN_MASK) | TLB_WR; - - if (cache) - data |= (TLB_EX | TLB_I); - else - data |= (TLB_G | TLB_I); - - tag = (va & TLB_EPN_MASK) | TLB_VALID | pagesz; - - for (i = 0; i < PPC4XX_TLB_SIZE; i++) { - if (pin_table[i].e_pinned == FALSE) { - found = TRUE; - break; - } - } +extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long); - if (found) { - /* printk("Pinning %#x -> %#x in entry %d...\n", va, pa, i); */ - asm("tlbwe %0,%1,1" : : "r" (data), "r" (i)); - asm("tlbwe %0,%1,0" : : "r" (tag), "r" (i)); - asm("isync"); - pin_table[i].e_pinned = found; - } - mtspr(SPRN_PID, opid); - return; -} - -void -PPC4xx_tlb_unpin(unsigned long va, unsigned long pa, int size) +/* + * () + * + * Description: + * This routine... + * + * Input(s): + * + * + * Output(s): + * + * + * Returns: + * + * + */ +static inline void +PPC4xx_tlb_write(unsigned long tag, unsigned long data, unsigned int index) { - /* XXX - To beimplemented. */ + asm("tlbwe %0,%1,1" : : "r" (data), "r" (index)); + asm("tlbwe %0,%1,0" : : "r" (tag), "r" (index)); } +/* + * () + * + * Description: + * This routine... + * + * Input(s): + * + * + * Output(s): + * + * + * Returns: + * + * + */ void -PPC4xx_tlb_flush_all(void) +PPC4xx_flush_tlb_all(void) { int i; - unsigned long flags, opid; + unsigned long flags, pid; save_flags(flags); cli(); - opid = mfspr(SPRN_PID); + pid = mfspr(SPRN_PID); mtspr(SPRN_PID, 0); - for (i = 0; i < PPC4XX_TLB_SIZE; i++) { - unsigned long ov = 0; + for (i = pinned; i < PPC4XX_TLB_SIZE; i++) { + PPC4xx_tlb_write(0, 0, i); + } + asm("sync;isync"); - if (pin_table[i].e_pinned) - continue; + mtspr(SPRN_PID, pid); + restore_flags(flags); +} - asm("tlbwe %0,%1,0" : : "r" (ov), "r" (i)); - asm("tlbwe %0,%1,1" : : "r" (ov), "r" (i)); +/* + * () + * + * Description: + * This routine... + * + * Input(s): + * + * + * Output(s): + * + * + * Returns: + * + * + */ +void +PPC4xx_dtlb_miss(struct pt_regs *regs) +{ + unsigned long addr = mfspr(SPRN_DEAR); + int write = mfspr(SPRN_ESR) & ESR_DST; + + if (PPC4xx_tlb_miss(regs, addr, write) < 0) { + sti(); + do_page_fault(regs, addr, write); + cli(); } + +} - asm("sync;isync"); +/* + * () + * + * Description: + * This routine... + * + * Input(s): + * + * + * Output(s): + * + * + * Returns: + * + * + */ +void +PPC4xx_itlb_miss(struct pt_regs *regs) +{ + unsigned long addr = regs->nip; - mtspr(SPRN_PID, opid); - restore_flags(flags); + if (PPC4xx_tlb_miss(regs, addr, 0) < 0) { + sti(); + do_page_fault(regs, addr, 0); + cli(); + } } +/* + * () + * + * Description: + * This routine... + * + * Input(s): + * + * + * Output(s): + * + * + * Returns: + * + * + */ void -PPC4xx_tlb_flush(unsigned long va, int pid) +PPC4xx_tlb_pin(unsigned long va, unsigned long pa, int pagesz, int cache) { - unsigned long i, tag, flags, found = 1, opid; + unsigned long tag, data; + unsigned long opid; - save_flags(flags); - cli(); + if (pinned >= PPC4XX_TLB_SIZE) + return; opid = mfspr(SPRN_PID); - mtspr(SPRN_PID, pid); + mtspr(SPRN_PID, 0); - asm("tlbsx. %0,0,%2;beq 1f;li %1,0;1:" : "=r" (i), "=r" (found) : "r" (va)); + data = (pa & TLB_RPN_MASK) | TLB_WR; - if (found && pin_table[i].e_pinned == 0) { - asm("tlbre %0,%1,0" : "=r" (tag) : "r" (i)); - tag &= ~ TLB_VALID; - asm("tlbwe %0,%1,0" : : "r" (tag), "r" (i)); - } + if (cache) + data |= (TLB_EX); + else + data |= (TLB_G | TLB_I); - mtspr(SPRN_PID, opid); + tag = (va & TLB_EPN_MASK) | TLB_VALID | pagesz; - restore_flags(flags); + PPC4xx_tlb_write(tag, data, pinned++); + + mtspr(SPRN_PID, opid); + return; } -#if 0 /* - * TLB miss handling code. + * () + * + * Description: + * This routine... + * + * Input(s): + * + * + * Output(s): + * + * + * Returns: + * + * */ +void +PPC4xx_tlb_unpin(unsigned long va, unsigned long pa, int size) +{ + /* XXX - To be implemented. */ +} /* - * Handle TLB faults. We should push this back to assembly code eventually. - * Caller is responsible for turning off interrupts ... + * () + * + * Description: + * This routine... + * + * Input(s): + * + * + * Output(s): + * + * + * Returns: + * + * */ static inline void -tlbDropin(unsigned long tlbhi, unsigned long tlblo) { - /* - * Avoid the divide at the slight cost of a little too - * much emphasis on the last few entries. - */ - unsigned long rand = mfspr(SPRN_TBLO); - rand &= 0x3f; - rand += NTLB_WIRED; - if (rand >= NTLB) - rand -= NTLB_WIRED; - - asm("tlbwe %0,%1,1" : : "r" (tlblo), "r" (rand)); - asm("tlbwe %0,%1,0" : : "r" (tlbhi), "r" (rand)); - asm("isync;sync"); -} +PPC4xx_tlb_update(unsigned long addr, pte_t *pte) +{ + unsigned long data, tag, rand; + int i, found = 1; -static inline void -mkTlbEntry(unsigned long addr, pte_t *pte) { - unsigned long tlbhi; - unsigned long tlblo; - int found = 1; - int idx; + /* Construct the hardware TLB entry from the Linux-style PTE */ - /* - * Construct the TLB entry. - */ - tlbhi = addr & ~(PAGE_SIZE-1); - tlblo = virt_to_phys(pte_page(*pte)) & TLBLO_RPN; - if (pte_val(*pte) & _PAGE_HWWRITE) - tlblo |= TLBLO_WR; - if (pte_val(*pte) & _PAGE_NO_CACHE) - tlblo |= TLBLO_I; - tlblo |= TLBLO_EX; - if (addr < KERNELBASE) - tlblo |= TLBLO_Z_USER; - tlbhi |= TLBHI_PGSZ_4K; - tlbhi |= TLBHI_VALID; + tag = tag = (addr & PAGE_MASK) | TLB_VALID | TLB_PAGESZ(PAGESZ_4K); + data = data = (pte_val(*pte) & PAGE_MASK) | TLB_EX | TLB_WR; - /* - * See if a match already exists in the TLB. - */ - asm("tlbsx. %0,0,%2;beq 1f;li %1,0;1:" : "=r" (idx), "=r" (found) : "r" (tlbhi)); - if (found) { - /* - * Found an existing entry. Just reuse the index. - */ - asm("tlbwe %0,%1,0" : : "r" (tlbhi), "r" (idx)); - asm("tlbwe %0,%1,1" : : "r" (tlblo), "r" (idx)); - } - else { - /* - * Do the more expensive operation - */ - tlbDropin(tlbhi, tlblo); - } -} - -/* - * Mainline of the TLB miss handler. The above inline routines should fold into - * this one, eliminating most function call overhead. - */ -#ifdef TLBMISS_DEBUG -volatile unsigned long miss_start; -volatile unsigned long miss_end; -#endif - -static inline int tlbMiss(struct pt_regs *regs, unsigned long badaddr, int wasWrite) -{ - int spid, ospid; - struct mm_struct *mm; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - if (!user_mode(regs) && (badaddr >= KERNELBASE)) { - mm = task[0]->mm; - spid = 0; -#ifdef TLBMISS_DEBUG - miss_start = 0; -#endif - } - else { - mm = current->mm; - spid = mfspr(SPRN_PID); -#ifdef TLBMISS_DEBUG - miss_start = 1; -#endif - } -#ifdef TLBMISS_DEBUG - store_cache_range((unsigned long)&miss_start, sizeof(miss_start)); +#if 0 + if (pte_val(*pte) & _PAGE_HWWRITE) + data |= TLB_WR; #endif - pgd = pgd_offset(mm, badaddr); - if (pgd_none(*pgd)) - goto NOGOOD; - - pmd = pmd_offset(pgd, badaddr); - if (pmd_none(*pmd)) - goto NOGOOD; - - pte = pte_offset(pmd, badaddr); - if (pte_none(*pte)) - goto NOGOOD; - if (!pte_present(*pte)) - goto NOGOOD; -#if 1 - prohibit_if_guarded(badaddr, sizeof(int)); -#endif - if (wasWrite) { - if (!pte_write(*pte)) { - goto NOGOOD; - } - set_pte(pte, pte_mkdirty(*pte)); - } - set_pte(pte, pte_mkyoung(*pte)); + if (pte_val(*pte) & _PAGE_NO_CACHE) + data |= TLB_I; - ospid = mfspr(SPRN_PID); - mtspr(SPRN_PID, spid); - mkTlbEntry(badaddr, pte); - mtspr(SPRN_PID, ospid); - -#ifdef TLBMISS_DEBUG - miss_end = 0; - store_cache_range((unsigned long)&miss_end, sizeof(miss_end)); -#endif - return 0; + if (pte_val(*pte) & _PAGE_GUARDED) + data |= TLB_G; -NOGOOD: -#ifdef TLBMISS_DEBUG - miss_end = 1; - store_cache_range((unsigned long)&miss_end, sizeof(miss_end)); -#endif - return 1; -} + if (addr < KERNELBASE) + data |= TLB_ZSEL(1); -/* - * End TLB miss handling code. - */ -/* ---------- */ + /* Attempt to match the new tag to an existing entry in the TLB. */ -/* - * Used to flush the TLB if the page fault handler decides to change - * something. - */ -void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) { - int spid; - unsigned long flags; + asm("tlbsx. %0,0,%2;" + "beq 1f;" + "li %1,0;1:" : "=r" (i), "=r" (found) : "r" (tag)); - save_flags(flags); - cli(); + /* + * If we found a match for the tag, reuse the entry index and update + * the tag and data portions. Otherwise, we did not find a match. Use + * the lower 5 bits of the lower time base register as a pseudo-random + * index into the TLB and replace the entry at that index. + */ - if (addr >= KERNELBASE) - spid = 0; - else - spid = vma->vm_mm->context; - tlbFlush1(addr, spid); + if (found) { + PPC4xx_tlb_write(tag, data, i); + } else { + rand = mfspr(SPRN_TBLO) & (PPC4XX_TLB_SIZE - 1); + rand += pinned; + if (rand >= PPC4XX_TLB_SIZE) + rand -= pinned; - restore_flags(flags); + PPC4xx_tlb_write(tag, data, rand); + asm("isync;sync"); + } } /* - * Given a virtual address in the current address space, make - * sure the associated physical page is present in memory, - * and if the data is to be modified, that any copy-on-write - * actions have taken place. + * () + * + * Description: + * This routine... + * + * Input(s): + * + * + * Output(s): + * + * + * Returns: + * + * */ -unsigned long make_page_present(unsigned long p, int rw) { +static int +PPC4xx_tlb_miss(struct pt_regs *regs, unsigned long addr, int write) +{ + unsigned long spid, ospid; + struct mm_struct *mm; + pgd_t *pgd; + pmd_t *pmd; pte_t *pte; - char c; - get_user(c, (char *) p); + if (!user_mode(regs) && (addr >= KERNELBASE)) { + mm = &init_mm; + spid = 0; + } else { + mm = current->mm; + spid = mfspr(SPRN_PID); + } + + pgd = pgd_offset(mm, addr); + if (pgd_none(*pgd)) + goto bad; + + pmd = pmd_offset(pgd, addr); + if (pmd_none(*pmd)) + goto bad; - pte = findPTE(current->mm, p); + pte = pte_offset(pmd, addr); if (pte_none(*pte) || !pte_present(*pte)) - debug("make_page_present didn't load page", 0); + goto bad; - if (rw) { - /* - * You have to write-touch the page, so that - * zero-filled pages are forced to be copied - * rather than still pointing at the zero - * page. - */ - extern void tlbFlush1(unsigned long, int); - tlbFlush1(p, get_context()); - put_user(c, (char *) p); - if (!pte_write(*pte)) - debug("make_page_present didn't make page writable", 0); + if (write) { + if (!pte_write(*pte)) + goto bad; - tlbFlush1(p, get_context()); + set_pte(pte, pte_mkdirty(*pte)); } - return pte_page(*pte); -} - -void DataTLBMissException(struct pt_regs *regs) -{ - unsigned long badaddr = mfspr(SPRN_DEAR); - int wasWrite = mfspr(SPRN_ESR) & 0x800000; - if (tlbMiss(regs, badaddr, wasWrite)) { - sti(); - do_page_fault(regs, badaddr, wasWrite); - cli(); - } -} + set_pte(pte, pte_mkyoung(*pte)); -void InstructionTLBMissException(struct pt_regs *regs) -{ - if (!current) { - debug("ITLB Miss with no current task", regs); - sti(); - bad_page_fault(regs, regs->nip); - cli(); - return; - } - if (tlbMiss(regs, regs->nip, 0)) { - sti(); - do_page_fault(regs, regs->nip, 0); - cli(); - } + ospid = mfspr(SPRN_PID); + mtspr(SPRN_PID, spid); + PPC4xx_tlb_update(addr, pte); + mtspr(SPRN_PID, ospid); + + return (0); +bad: + return (-1); } - -void DataPageFault(struct pt_regs *regs) -{ - unsigned long badaddr = mfspr(SPRN_DEAR); - int wasWrite = mfspr(SPRN_ESR) & 0x800000; - sti(); - do_page_fault(regs, badaddr, wasWrite); - cli(); -} - -void InstructionPageFault(struct pt_regs *regs) -{ - if (!current) { - debug("ITLB fault with no current task", regs); - sti(); - bad_page_fault(regs, regs->nip); - cli(); - return; - } - sti(); - do_page_fault(regs, regs->nip, 0); - cli(); -} -#endif diff -u --recursive --new-file v2.3.42/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.3.42/linux/arch/ppc/mm/init.c Tue Jan 11 22:31:38 2000 +++ linux/arch/ppc/mm/init.c Wed Feb 9 20:08:09 2000 @@ -107,7 +107,6 @@ static void mapin_ram(void); void map_page(unsigned long va, unsigned long pa, int flags); extern void die_if_kernel(char *,struct pt_regs *,long); -extern void show_net_buffers(void); struct mem_pieces phys_mem; @@ -281,9 +280,6 @@ printk("%d pages swap cached\n",cached); printk("%d pages in page table cache\n",(int)pgtable_cache_size); show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif printk("%-8s %3s %8s %8s %8s %9s %8s", "Process", "Pid", "Ctx", "Ctx<<4", "Last Sys", "pc", "task"); #ifdef __SMP__ @@ -643,7 +639,9 @@ wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX; bat[1].word[0] = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */ bat[1].word[1] = phys | wimgxpp; +#ifndef CONFIG_KGDB /* want user access for breakpoints */ if (flags & _PAGE_USER) +#endif bat[1].bat.batu.vp = 1; if (flags & _PAGE_GUARDED) { /* G bit must be zero in IBATs */ @@ -732,6 +730,10 @@ * don't get ASID compares on kernel space. */ f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED; +#ifdef CONFIG_KGDB + /* Allows stub to set breakpoints everywhere */ + f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; +#else if ((char *) v < _stext || (char *) v >= etext) f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE; #ifndef CONFIG_8xx @@ -740,6 +742,7 @@ forces R/W kernel access */ f |= _PAGE_USER; #endif /* CONFIG_8xx */ +#endif /* CONFIG_KGDB */ map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; @@ -844,6 +847,8 @@ } #endif +extern boot_infos_t *disp_bi; + /* * Do very early mm setup such as finding the size of memory * and setting up the hash table. @@ -855,25 +860,45 @@ void __init MMU_init(void) { + /* + * The Zone Protection Register (ZPR) defines how protection will + * be applied to every page which is a member of a given zone. At + * present, we utilize only two of the 4xx's zones. The first, zone + * 0, is set at '00b and only allows access in supervisor-mode based + * on the EX and WR bits. No user-mode access is allowed. The second, + * zone 1, is set at '10b and in supervisor-mode allows access + * without regard to the EX and WR bits. In user-mode, access is + * allowed based on the EX and WR bits. + */ + + mtspr(SPRN_ZPR, 0x2aaaaaaa); + + /* Hardwire any TLB entries necessary here. */ + PPC4xx_tlb_pin(KERNELBASE, 0, TLB_PAGESZ(PAGESZ_16M), 1); - PPC4xx_tlb_pin(OAKNET_IO_BASE, OAKNET_IO_BASE, TLB_PAGESZ(PAGESZ_4K), 0); - end_of_DRAM = oak_find_end_of_memory(); - /* Map in all of RAM starting at KERNELBASE */ + /* + * Find the top of physical memory and map all of it in starting + * at KERNELBASE. + */ + end_of_DRAM = oak_find_end_of_memory(); mapin_ram(); - /* Zone 0 - kernel (above 0x80000000), zone 1 - user */ + /* + * Set up the real-mode cache parameters for the exception vector + * handlers (which are run in real-mode). + */ - mtspr(SPRN_ZPR, 0x2aaaaaaa); - mtspr(SPRN_DCWR, 0x00000000); /* all caching is write-back */ + mtspr(SPRN_DCWR, 0x00000000); /* All caching is write-back */ - /* Cache 128MB of space starting at KERNELBASE. */ + /* + * Cache instruction and data space where the exception + * vectors and the kernel live in real-mode. + */ - mtspr(SPRN_DCCR, 0x00000000); - /* flush_instruction_cache(); XXX */ - mtspr(SPRN_ICCR, 0x00000000); - + mtspr(SPRN_DCCR, 0x80000000); /* 128 MB of data space at 0x0. */ + mtspr(SPRN_ICCR, 0x80000000); /* 128 MB of instr. space at 0x0. */ } #else void __init MMU_init(void) @@ -895,7 +920,11 @@ if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); +#ifdef CONFIG_PPC64 + _SDR1 = 0; /* temporary hack to just use bats -- Cort */ +#else _SDR1 = __pa(Hash) | (Hash_mask >> 10); +#endif ioremap_base = 0xf8000000; if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301); @@ -916,8 +945,14 @@ break; case _MACH_chrp: setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE); +#ifdef CONFIG_PPC64 + /* temporary hack to get working until page tables are stable -- Cort*/ + setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE); + setbat(3, 0xd0000000, 0xd0000000, 0x10000000, IO_PAGE); +#else setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE); +#endif break; case _MACH_Pmac: #if 0 @@ -929,6 +964,10 @@ setbat(0, base, base, 0x100000, IO_PAGE); } #endif +#if 0 + setbat(0, disp_bi->dispDeviceBase, disp_bi->dispDeviceBase, 0x100000, IO_PAGE); + disp_bi->logicalDisplayBase = disp_bi->dispDeviceBase; +#endif ioremap_base = 0xf0000000; break; case _MACH_apus: @@ -1087,6 +1126,8 @@ void __init mem_init(void) { + extern char *sysmap; + extern unsigned long sysmap_size; unsigned long addr; int codepages = 0; int datapages = 0; @@ -1116,6 +1157,11 @@ addr += PAGE_SIZE) SetPageReserved(mem_map + MAP_NR(addr)); #endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */ + if ( sysmap_size ) + for (addr = (unsigned long)sysmap; + addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ; + addr += PAGE_SIZE) + SetPageReserved(mem_map + MAP_NR(addr)); for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM; addr += PAGE_SIZE) { @@ -1131,10 +1177,8 @@ } printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n", - (unsigned long) nr_free_pages << (PAGE_SHIFT-10), - codepages << (PAGE_SHIFT-10), - datapages << (PAGE_SHIFT-10), - initpages << (PAGE_SHIFT-10), + (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), + codepages, datapages, initpages, PAGE_OFFSET, (unsigned long) end_of_DRAM); mem_init_done = 1; } @@ -1153,7 +1197,7 @@ unsigned long a, total; /* max amount of RAM we allow -- Cort */ -#define RAM_LIMIT (768<<20) +#define RAM_LIMIT (64<<20) memory_node = find_devices("memory"); if (memory_node == NULL) { @@ -1384,7 +1428,7 @@ { if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345); Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); - __clear_user(Hash, Hash_size); + /*__clear_user(Hash, Hash_size);*/ /* * Patch up the instructions in head.S:hash_page diff -u --recursive --new-file v2.3.42/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c --- v2.3.42/linux/arch/ppc/xmon/start.c Fri Jan 28 15:09:07 2000 +++ linux/arch/ppc/xmon/start.c Wed Feb 9 19:43:47 2000 @@ -8,19 +8,34 @@ #include #include #include +#include #include #include +#include #include static volatile unsigned char *sccc, *sccd; unsigned long TXRDY, RXRDY; extern void xmon_printf(const char *fmt, ...); -extern void map_bootx_text(void); extern void drawchar(char); extern void drawstring(const char *str); +static int xmon_expect(const char *str, unsigned int timeout); static int console = 0; static int use_screen = 0; +static int via_modem = 0; +static int xmon_use_sccb = 0; +static struct device_node *macio_node; + +#define TB_SPEED 25000000 + +static inline unsigned int readtb(void) +{ + unsigned int ret; + + asm volatile("mftb %0" : "=r" (ret) :); + return ret; +} void buf_access(void) { @@ -36,17 +51,19 @@ if ( _machine == _MACH_Pmac ) { struct device_node *np; - extern boot_infos_t *boot_infos; unsigned long addr; - #ifdef CONFIG_BOOTX_TEXT - if (boot_infos != 0 && find_via_pmu()) { - printk("xmon uses screen and keyboard\n"); + extern boot_infos_t *disp_bi; + + /* needs to be hacked if xmon_printk is to be used + from within find_via_pmu() */ + if (!via_modem && disp_bi && find_via_pmu()) { + drawstring("xmon uses screen and keyboard\n"); use_screen = 1; - map_bootx_text(); return; } #endif + #ifdef CHRP_ESCC addr = 0xc1013020; #else @@ -57,9 +74,10 @@ np = find_devices("mac-io"); if (np && np->n_addrs) { + macio_node = np; addr = np->addrs[0].address + 0x13000; - /* use the B channel on the iMac, A channel on others */ - if (addr >= 0xf0000000) + /* use the B channel on the iMac */ + if (!xmon_use_sccb) addr += 0x20; /* use A channel */ } base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE); @@ -70,22 +88,22 @@ sccd = sccc + (0xf3013030 - 0xf3013020); #endif } - else if ( _machine & _MACH_chrp ) + else if ( _machine & _MACH_gemini ) { /* should already be mapped by the kernel boot */ - sccc = (volatile unsigned char *) (isa_io_base + 0x3fd); - sccd = (volatile unsigned char *) (isa_io_base + 0x3f8); + sccc = (volatile unsigned char *) 0xffeffb0d; + sccd = (volatile unsigned char *) 0xffeffb08; TXRDY = 0x20; RXRDY = 1; + console = 1; } - else if ( _machine & _MACH_gemini ) + else { /* should already be mapped by the kernel boot */ - sccc = (volatile unsigned char *) 0xffeffb0d; - sccd = (volatile unsigned char *) 0xffeffb08; + sccc = (volatile unsigned char *) (isa_io_base + 0x3fd); + sccd = (volatile unsigned char *) (isa_io_base + 0x3f8); TXRDY = 0x20; RXRDY = 1; - console = 1; } } @@ -98,7 +116,7 @@ xmon_write(void *handle, void *ptr, int nb) { char *p = ptr; - int i, ct; + int i, c, ct; #ifdef CONFIG_BOOTX_TEXT if (use_screen) { @@ -111,20 +129,26 @@ if (!scc_initialized) xmon_init_scc(); for (i = 0; i < nb; ++i) { -#ifdef CONFIG_ADB + ct = 0; while ((*sccc & TXRDY) == 0) +#ifdef CONFIG_ADB if (sys_ctrler == SYS_CTRLER_PMU) pmu_poll(); +#else + ; #endif /* CONFIG_ADB */ - buf_access(); - if ( console && (*p != '\r')) - printk("%c", *p); - ct = 0; - if ( *p == '\n') + c = p[i]; + if (c == '\n' && !ct) { + c = '\r'; ct = 1; - *sccd = *p++; - if ( ct ) - xmon_write(handle, "\r", 1); + --i; + } else { + if (console) + printk("%c", c); + ct = 0; + } + buf_access(); + *sccd = c; } return i; } @@ -206,36 +230,49 @@ if (!scc_initialized) xmon_init_scc(); for (i = 0; i < nb; ++i) { -#ifdef CONFIG_ADB while ((*sccc & RXRDY) == 0) +#ifdef CONFIG_ADB if (sys_ctrler == SYS_CTRLER_PMU) pmu_poll(); +#else + ; #endif /* CONFIG_ADB */ buf_access(); -#if 0 - if ( 0/*console*/ ) - *p++ = ppc_md.kbd_getkeycode(); - else -#endif *p++ = *sccd; } return i; } +int +xmon_read_poll(void) +{ + if ((*sccc & RXRDY) == 0) { +#ifdef CONFIG_ADB + if (sys_ctrler == SYS_CTRLER_PMU) + pmu_poll(); +#else + ; +#endif + return -1; + } + buf_access(); + return *sccd; +} + static unsigned char scc_inittab[] = { 13, 0, /* set baud rate divisor */ 12, 1, 14, 1, /* baud rate gen enable, src=rtxc */ 11, 0x50, /* clocks = br gen */ - 5, 0x6a, /* tx 8 bits, assert RTS */ - 4, 0x44, /* x16 clock, 1 stop */ + 5, 0xea, /* tx 8 bits, assert DTR & RTS */ + 4, 0x46, /* x16 clock, 1 stop */ 3, 0xc1, /* rx enable, 8 bits */ }; void xmon_init_scc() { - if ( _machine & (_MACH_chrp|_MACH_gemini) ) + if ( _machine == _MACH_chrp ) { sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ sccd[0] = 3; eieio(); /* DLL = 38400 baud */ @@ -248,6 +285,14 @@ { int i, x; + if (macio_node != 0) { + unsigned int t0; + + feature_set(macio_node, FEATURE_Modem_power); + t0 = readtb(); + while (readtb() - t0 < 3*TB_SPEED) + eieio(); + } for (i = 20000; i != 0; --i) { x = *sccc; eieio(); } @@ -259,6 +304,18 @@ } } scc_initialized = 1; + if (via_modem) { + for (;;) { + xmon_write(0, "ATE1V1\r", 7); + if (xmon_expect("OK", 5)) { + xmon_write(0, "ATA\r", 4); + if (xmon_expect("CONNECT", 40)) + break; + } + xmon_write(0, "+++", 3); + xmon_expect("OK", 3); + } + } } #if 0 @@ -330,6 +387,35 @@ static char line[256]; static char *lineptr; static int lineleft; + +int xmon_expect(const char *str, unsigned int timeout) +{ + int c; + unsigned int t0; + + timeout *= TB_SPEED; + t0 = readtb(); + do { + lineptr = line; + for (;;) { + c = xmon_read_poll(); + if (c == -1) { + if (readtb() - t0 > timeout) { + printk("timeout\n"); + return 0; + } + continue; + } + if (c == '\n') + break; + printk("%c", c); + if (c != '\r' && lineptr < &line[sizeof(line) - 1]) + *lineptr++ = c; + } + *lineptr = 0; + } while (strstr(line, str) == NULL); + return 1; +} int xmon_getchar(void) diff -u --recursive --new-file v2.3.42/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c --- v2.3.42/linux/arch/ppc/xmon/xmon.c Fri Jan 21 18:19:16 2000 +++ linux/arch/ppc/xmon/xmon.c Wed Feb 9 19:43:47 2000 @@ -1344,3 +1344,31 @@ { lineptr = str; } + +char last[64]; +char * +lookup_addr(unsigned long addr) +{ + extern char *sysmap; + extern unsigned long sysmap_size; + char *c = sysmap; + unsigned long cmp; + + if ( !sysmap || !sysmap_size ) + return NULL; + + /* adjust if addr is relative to kernelbase */ + if ( addr < PAGE_OFFSET ) + addr += PAGE_OFFSET; + + cmp = simple_strtoul(c, &c, 8); + strcpy( last, strsep( &c, "\n")); + while ( c < (sysmap+sysmap_size) ) + { + cmp = simple_strtoul(c, &c, 8); + if ( cmp < addr ) + break; + strcpy( last, strsep( &c, "\n")); + } + return last; +} diff -u --recursive --new-file v2.3.42/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c --- v2.3.42/linux/arch/sh/mm/init.c Sun Nov 7 16:37:34 1999 +++ linux/arch/sh/mm/init.c Wed Feb 9 20:08:09 2000 @@ -41,7 +41,6 @@ static unsigned long totalram_pages = 0; static unsigned long totalhigh_pages = 0; -extern void show_net_buffers(void); extern unsigned long init_smp_mappings(unsigned long); /* @@ -173,9 +172,6 @@ printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } /* References to section boundaries */ diff -u --recursive --new-file v2.3.42/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.3.42/linux/arch/sparc/config.in Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/config.in Thu Feb 10 12:16:37 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.84 2000/01/31 21:10:04 davem Exp $ +# $Id: config.in,v 1.86 2000/02/10 02:51:10 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -21,7 +21,7 @@ bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 if [ "$CONFIG_SUN4" != "y" ]; then - bool ' Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI + bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI source drivers/pci/Config.in fi @@ -118,11 +118,24 @@ comment 'SCSI support type (disk, tape, CDrom)' dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + + if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then + int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 + fi + dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + + if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then + int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 + fi + dep_tristate ' SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 fi + dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' @@ -130,6 +143,7 @@ bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS + bool ' SCSI logging facility' CONFIG_SCSI_LOGGING mainmenu_option next_comment comment 'SCSI low-level drivers' diff -u --recursive --new-file v2.3.42/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.3.42/linux/arch/sparc/defconfig Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/defconfig Thu Feb 10 12:16:37 2000 @@ -175,9 +175,12 @@ # SCSI support type (disk, tape, CDrom) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=m # @@ -185,6 +188,7 @@ # CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers @@ -245,7 +249,6 @@ CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set -# CONFIG_BFS_FS_WRITE is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set diff -u --recursive --new-file v2.3.42/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v2.3.42/linux/arch/sparc/kernel/ioport.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/kernel/ioport.c Tue Feb 8 18:23:13 2000 @@ -1,10 +1,28 @@ -/* $Id: ioport.c,v 1.30 2000/01/28 13:41:55 jj Exp $ +/* $Id: ioport.c,v 1.31 2000/02/06 22:55:32 zaitcev Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * * 1996: sparc_free_io, 1999: ioremap()/iounmap() by Pete Zaitcev. + * + * 2000/01/29 + * zait: as long as pci_alloc_consistent produces something addressable, + * things are ok. + * rth: no, it is relevant, because get_free_pages returns you a + * pointer into the big page mapping + * zait: so what? + * zait: remap_it_my_way(virt_to_phys(get_free_page())) + * Hmm + * Suppose I did this remap_it_my_way(virt_to_phys(get_free_page())). + * So far so good. + * Now, driver calls pci_free_consistent(with result of + * remap_it_my_way()). + * How do you find the address to pass to free_pages()? + * zait: walk the page tables? It's only two or three level after all. + * zait: you have to walk them anyway to remove the mapping. + * Hmm + * Sounds reasonable */ #include @@ -15,6 +33,8 @@ #include #include #include +#include /* struct pci_dev */ +#include #include #include @@ -23,8 +43,8 @@ #include #include -struct resource *sparc_find_resource_bystart(struct resource *, unsigned long); -struct resource *sparc_find_resource_by_hit(struct resource *, unsigned long); +struct resource *_sparc_find_resource(struct resource *r, unsigned long); +int _sparc_len2order(unsigned long len); static void *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz); static void *_sparc_alloc_io(unsigned int busno, unsigned long phys, @@ -32,15 +52,22 @@ static void _sparc_free_io(struct resource *res); /* This points to the next to use virtual memory for DVMA mappings */ -static struct resource sparc_dvma = { +static struct resource _sparc_dvma = { "sparc_dvma", DVMA_VADDR, DVMA_VADDR + DVMA_LEN - 1 }; /* This points to the start of I/O mappings, cluable from outside. */ - struct resource sparc_iomap = { +/*ext*/ struct resource sparc_iomap = { "sparc_iomap", IOBASE_VADDR, IOBASE_END-1 }; /* + * BTFIXUP would do as well but it seems overkill for the case. + */ +static void (*_sparc_mapioaddr)(unsigned long pa, unsigned long va, + int bus, int ro); +static void (*_sparc_unmapioaddr)(unsigned long va); + +/* * Our mini-allocator... * Boy this is gross! We need it because we must map I/O for * timers and interrupt controller before the kmalloc is available. @@ -77,55 +104,6 @@ } /* - */ -extern void sun4c_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly); -extern void srmmu_mapioaddr(unsigned long, unsigned long, int bus_type, int rdonly); - -static void mapioaddr(unsigned long physaddr, unsigned long virt_addr, - int bus, int rdonly) -{ - switch(sparc_cpu_model) { - case sun4c: - case sun4: - sun4c_mapioaddr(physaddr, virt_addr, bus, rdonly); - break; - case sun4m: - case sun4d: - case sun4e: - srmmu_mapioaddr(physaddr, virt_addr, bus, rdonly); - break; - default: - printk("mapioaddr: Trying to map IO space for unsupported machine.\n"); - printk("mapioaddr: sparc_cpu_model = %d\n", sparc_cpu_model); - printk("mapioaddr: Halting...\n"); - halt(); - }; - return; -} - -extern void srmmu_unmapioaddr(unsigned long virt); -extern void sun4c_unmapioaddr(unsigned long virt); - -static void unmapioaddr(unsigned long virt_addr) -{ - switch(sparc_cpu_model) { - case sun4c: - case sun4: - sun4c_unmapioaddr(virt_addr); - break; - case sun4m: - case sun4d: - case sun4e: - srmmu_unmapioaddr(virt_addr); - break; - default: - printk("unmapioaddr: sparc_cpu_model = %d, halt...\n", sparc_cpu_model); - halt(); - }; - return; -} - -/* * These are typically used in PCI drivers * which are trying to be cross-platform. * @@ -147,7 +125,7 @@ unsigned long vaddr = (unsigned long) virtual & PAGE_MASK; struct resource *res; - if ((res = sparc_find_resource_bystart(&sparc_iomap, vaddr)) == NULL) { + if ((res = _sparc_find_resource(&sparc_iomap, vaddr)) == NULL) { printk("free_io/iounmap: cannot free %lx\n", vaddr); return; } @@ -161,7 +139,6 @@ } /* - * Davem's version of sbus_ioremap. */ unsigned long sbus_ioremap(struct resource *phyres, unsigned long offset, unsigned long size, char *name) @@ -218,8 +195,6 @@ } /* - * This is called from _sparc_alloc_io only, we left it separate - * in case Davem changes his mind about interface to sbus_ioremap(). */ static void * _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) @@ -240,7 +215,7 @@ va = res->start; pa &= PAGE_MASK; for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { - mapioaddr(pa, va, bus, 0); + (*_sparc_mapioaddr)(pa, va, bus, 0); va += PAGE_SIZE; pa += PAGE_SIZE; } @@ -270,7 +245,7 @@ plen = res->end - res->start + 1; while (plen != 0) { plen -= PAGE_SIZE; - unmapioaddr(res->start + plen); + (*_sparc_unmapioaddr)(res->start + plen); } release_resource(res); @@ -305,9 +280,7 @@ return NULL; } - for (order = 0; order < 6; order++) /* 2^6 pages == 256K */ - if ((1 << (order + PAGE_SHIFT)) >= len_total) - break; + order = _sparc_len2order(len_total); va = __get_free_pages(GFP_KERNEL, order); if (va == 0) { /* @@ -324,25 +297,17 @@ } memset((char*)res, 0, sizeof(struct resource)); - if (allocate_resource(&sparc_dvma, res, len_total, - sparc_dvma.start, sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { + if (allocate_resource(&_sparc_dvma, res, len_total, + _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { printk("sbus_alloc_consistent: cannot occupy 0x%lx", len_total); free_pages(va, order); kfree(res); return NULL; } - *dma_addrp = res->start; mmu_map_dma_area(va, res->start, len_total); - /* - * "Official" or "natural" address of pages we got is va. - * We want to return uncached range. We could make va[len] - * uncached but it's difficult to make cached back [P3: hmm] - * We use the artefact of sun4c, replicated everywhere else, - * that CPU can use bus addresses to access the same memory. - */ - res->name = (void *)va; /* XXX Ouch.. we got to hide it somewhere */ + *dma_addrp = res->start; return (void *)res->start; } @@ -350,9 +315,8 @@ { struct resource *res; unsigned long pgp; - int order; - if ((res = sparc_find_resource_bystart(&sparc_dvma, + if ((res = _sparc_find_resource(&_sparc_dvma, (unsigned long)p)) == NULL) { printk("sbus_free_consistent: cannot free %p\n", p); return; @@ -370,17 +334,14 @@ return; } - mmu_inval_dma_area((unsigned long)res->name, n); /* XXX Ouch */ - mmu_unmap_dma_area(ba, n); release_resource(res); + kfree(res); - pgp = (unsigned long) res->name; /* XXX Ouch */ - for (order = 0; order < 6; order++) - if ((1 << (order + PAGE_SHIFT)) >= n) - break; - free_pages(pgp, order); + /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ + pgp = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); + mmu_unmap_dma_area(ba, n); - kfree(res); + free_pages(pgp, _sparc_len2order(n)); } /* @@ -408,10 +369,10 @@ return 0; } memset((char*)res, 0, sizeof(struct resource)); - res->name = va; + res->name = va; /* XXX */ - if (allocate_resource(&sparc_dvma, res, len_total, - sparc_dvma.start, sparc_dvma.end, PAGE_SIZE) != 0) { + if (allocate_resource(&_sparc_dvma, res, len_total, + _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE) != 0) { printk("sbus_map_single: cannot occupy 0x%lx", len); kfree(res); return 0; @@ -431,7 +392,6 @@ if (len > 256*1024) { /* __get_free_pages() limit */ return 0; } -/* BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus) */ return mmu_get_scsi_one(va, len, sdev->bus); #endif } @@ -442,7 +402,7 @@ struct resource *res; unsigned long va; - if ((res = sparc_find_resource_bystart(&sparc_dvma, ba)) == NULL) { + if ((res = _sparc_find_resource(&_sparc_dvma, ba)) == NULL) { printk("sbus_unmap_single: cannot find %08x\n", (unsigned)ba); return; } @@ -461,14 +421,12 @@ kfree(res); #endif #if 1 /* "trampoline" version */ -/* BTFIXUPDEF_CALL(void, mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus) */ mmu_release_scsi_one(ba, n, sdev->bus); #endif } int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) { -/* BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */ mmu_get_scsi_sgl(sg, n, sdev->bus); /* @@ -480,65 +438,351 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) { -/* BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus) */ mmu_release_scsi_sgl(sg, n, sdev->bus); } -#endif /* - * P3: I think a partial flush is permitted... - * We are not too efficient at doing it though. - * - * If only DaveM understood a concept of an allocation cookie, - * we could avoid find_resource_by_hit() here and a major - * performance hit. */ void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size) { unsigned long va; struct resource *res; - res = sparc_find_resource_by_hit(&sparc_dvma, ba); + /* We do not need the resource, just print a message if invalid. */ + res = _sparc_find_resource(&_sparc_dvma, ba); if (res == NULL) panic("sbus_dma_sync_single: 0x%x\n", ba); - va = (unsigned long) res->name; - /* if (va == 0) */ - - mmu_inval_dma_area(va, (res->end - res->start) + 1); + va = (unsigned long) phys_to_virt(mmu_translate_dvma(ba)); + mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); } void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) { - printk("dma_sync_sg: not implemented yet\n"); + printk("sbus_dma_sync_sg: not implemented yet\n"); +} +#endif /* CONFIG_SBUS */ + +#ifdef CONFIG_PCI + +/* Allocate and map kernel buffer using consistent mode DMA for a device. + * hwdev should be valid struct pci_dev pointer for PCI devices. + */ +void *pci_alloc_consistent(struct pci_dev *pdev, size_t len, dma_addr_t *pba) +{ + unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; + unsigned long va; + struct resource *res; + int order; + + if (len == 0) { + return NULL; + } + if (len > 256*1024) { /* __get_free_pages() limit */ + return NULL; + } + + order = _sparc_len2order(len_total); + va = __get_free_pages(GFP_KERNEL, order); + if (va == 0) { + printk("pci_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT); + return NULL; + } + + if ((res = kmalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) { + free_pages(va, order); + printk("sbus_alloc_consistent: no core\n"); + return NULL; + } + memset((char*)res, 0, sizeof(struct resource)); + + if (allocate_resource(&_sparc_dvma, res, len_total, + _sparc_dvma.start, _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) { + printk("pci_alloc_consistent: cannot occupy 0x%lx", len_total); + free_pages(va, order); + kfree(res); + return NULL; + } + + mmu_inval_dma_area(va, len_total); + +#if 1 +/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %x\n", + (long)va, (long)res->start, (long)virt_to_phys(va), len_total); +#endif + { + unsigned long xva, xpa; + xva = res->start; + xpa = virt_to_phys(va); + while (len_total != 0) { + len_total -= PAGE_SIZE; + (*_sparc_mapioaddr)(xpa, xva, 0, 0); + xva += PAGE_SIZE; + xpa += PAGE_SIZE; + } + } + + *pba = virt_to_bus(va); + return (void *) res->start; } +/* Free and unmap a consistent DMA buffer. + * cpu_addr is what was returned from pci_alloc_consistent, + * size must be the same as what as passed into pci_alloc_consistent, + * and likewise dma_addr must be the same as what *dma_addrp was set to. + * + * References to the memory and mappings assosciated with cpu_addr/dma_addr + * past this call are illegal. + */ +void pci_free_consistent(struct pci_dev *pdev, size_t n, void *p, dma_addr_t ba) +{ + struct resource *res; + unsigned long pgp; + + if ((res = _sparc_find_resource(&_sparc_dvma, + (unsigned long)p)) == NULL) { + printk("sbus_free_consistent: cannot free %p\n", p); + return; + } + + if (((unsigned long)p & (PAGE_MASK-1)) != 0) { + printk("sbus_free_consistent: unaligned va %p\n", p); + return; + } + + n = (n + PAGE_SIZE-1) & PAGE_MASK; + if ((res->end-res->start)+1 != n) { + printk("sbus_free_consistent: region 0x%lx asked 0x%lx\n", + (long)((res->end-res->start)+1), (long)n); + return; + } + + pgp = (unsigned long) bus_to_virt(ba); + mmu_inval_dma_area(pgp, n); + { + int x; + for (x = 0; x < n; x += PAGE_SIZE) { + (*_sparc_unmapioaddr)(p + n); + } + } + + release_resource(res); + kfree(res); + + free_pages(pgp, _sparc_len2order(n)); +} + +/* Map a single buffer of the indicated size for DMA in streaming mode. + * The 32-bit bus address to use is returned. + * + * Once the device is given the dma address, the device owns this memory + * until either pci_unmap_single or pci_dma_sync_single is performed. + */ +dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size) +{ + return virt_to_bus(ptr); +} + +/* Unmap a single streaming mode DMA translation. The dma_addr and size + * must match what was provided for in a previous pci_map_single call. All + * other usages are undefined. + * + * After this call, reads by the cpu to the buffer are guarenteed to see + * whatever the device wrote there. + */ +void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size) +{ + /* Nothing to do... */ +} + +/* Map a set of buffers described by scatterlist in streaming + * mode for DMA. This is the scather-gather version of the + * above pci_map_single interface. Here the scatter gather list + * elements are each tagged with the appropriate dma address + * and length. They are obtained via sg_dma_{address,length}(SG). + * + * NOTE: An implementation may be able to use a smaller number of + * DMA address/length pairs than there are SG table elements. + * (for example via virtual mapping capabilities) + * The routine returns the number of addr/length pairs actually + * used, at most nents. + * + * Device ownership issues as mentioned above for pci_map_single are + * the same here. + */ +int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +{ + int n; + for (n = 0; n < nents; n++) { + sg->dvma_address = virt_to_bus(sg->address); + sg->dvma_length = sg->length; + sg++; + } + return nents; +} + +/* Unmap a set of streaming mode DMA translations. + * Again, cpu read rules concerning calls here are the same as for + * pci_unmap_single() above. + */ +void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents) +{ + /* Nothing to do... */ +} + +/* Make physical memory consistent for a single + * streaming mode DMA translation after a transfer. + * + * If you perform a pci_map_single() but wish to interrogate the + * buffer using the cpu, yet do not wish to teardown the PCI dma + * mapping, you must call this function before doing so. At the + * next point you give the PCI dma address back to the card, the + * device again owns the buffer. + */ +void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size) +{ + mmu_inval_dma_area((unsigned long)bus_to_virt(ba), + (size + PAGE_SIZE-1) & PAGE_MASK); +} + +/* Make physical memory consistent for a set of streaming + * mode DMA translations after a transfer. + * + * The same as pci_dma_sync_single but for a scatter-gather list, + * same rules and usage. + */ +void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +{ + while (nents) { + --nents; + mmu_inval_dma_area((unsigned long)sg->address, + (sg->dvma_length + PAGE_SIZE-1) & PAGE_MASK); + sg++; + } +} +#endif CONFIG_PCI + +#ifdef CONFIG_PROC_FS + +static int +_sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof, + void *data) +{ + char *p = buf, *e = buf + length; + struct resource *r; + const char *nm; + + for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { + if (p + 32 >= e) /* Better than nothing */ + break; + if ((nm = r->name) == 0) nm = "???"; + p += sprintf(p, "%08lx-%08lx: %s\n", r->start, r->end, nm); + } + + return p-buf; +} + +static struct proc_dir_entry _sparc_iomap_proc_entry = { + 0, /* Inode number - dynamic */ + 6, /* Length of the file name */ + "io_map", /* The file name */ + S_IFREG | S_IRUGO, /* File mode */ + 1, /* Number of links */ + 0, 0, /* The uid and gid for the file */ + 0, /* The size of the file reported by ls. */ + NULL, /* struct inode_operations * ops */ + NULL, /* get_info: backward compatibility */ + NULL, /* owner */ + NULL, NULL, NULL, /* linkage */ + &sparc_iomap, + _sparc_io_get_info, /* The read function for this file */ + NULL, + /* and more stuff */ +}; + +static struct proc_dir_entry _sparc_dvma_proc_entry = { + 0, /* Inode number - dynamic */ + 8, /* Length of the file name */ + "dvma_map", /* The file name */ + S_IFREG | S_IRUGO, /* File mode */ + 1, /* Number of links */ + 0, 0, /* The uid and gid for the file */ + 0, /* The size of the file reported by ls. */ + NULL, /* struct inode_operations * ops */ + NULL, /* get_info: backward compatibility */ + NULL, /* owner */ + NULL, NULL, NULL, /* linkage */ + &_sparc_dvma, + _sparc_io_get_info, + NULL, + /* some more stuff */ +}; + +#endif CONFIG_PROC_FS + /* * This is a version of find_resource and it belongs to kernel/resource.c. * Until we have agreement with Linus and Martin, it lingers here. * - * "same start" is more strict than "hit into" + * XXX Too slow. Can have 8192 DVMA pages on sun4m in the worst case. + * This probably warrants some sort of hashing. */ struct resource * -sparc_find_resource_bystart(struct resource *root, unsigned long start) +_sparc_find_resource(struct resource *root, unsigned long hit) { struct resource *tmp; - for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { - if (tmp->start == start) + for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { + if (tmp->start <= hit && tmp->end >= hit) return tmp; - } - return NULL; + } + return NULL; } -struct resource * -sparc_find_resource_by_hit(struct resource *root, unsigned long hit) +int +_sparc_len2order(unsigned long len) { - struct resource *tmp; + int order; - for (tmp = root->child; tmp != 0; tmp = tmp->sibling) { - if (tmp->start <= hit && tmp->end >= hit) - return tmp; - } - return NULL; + for (order = 0; order < 7; order++) /* 2^6 pages == 256K */ + if ((1 << (order + PAGE_SHIFT)) >= len) + return order; + printk("len2order: from %p: len %lu(0x%lx) yields order >=7.\n", + __builtin_return_address(0), len, len); + return 1; +} + +/* + * Necessary boot time initializations. + */ + +void ioport_init(void) +{ + extern void sun4c_mapioaddr(unsigned long, unsigned long, int, int); + extern void srmmu_mapioaddr(unsigned long, unsigned long, int, int); + extern void sun4c_unmapioaddr(unsigned long); + extern void srmmu_unmapioaddr(unsigned long); + + switch(sparc_cpu_model) { + case sun4c: + case sun4: + case sun4e: + _sparc_mapioaddr = sun4c_mapioaddr; + _sparc_unmapioaddr = sun4c_unmapioaddr; + break; + case sun4m: + case sun4d: + _sparc_mapioaddr = srmmu_mapioaddr; + _sparc_unmapioaddr = srmmu_unmapioaddr; + break; + default: + printk("ioport_init: cpu type %d is unknown.\n", + sparc_cpu_model); + halt(); + }; + +#ifdef CONFIG_PROC_FS + proc_register(&proc_root, &_sparc_iomap_proc_entry); + proc_register(&proc_root, &_sparc_dvma_proc_entry); +#endif } diff -u --recursive --new-file v2.3.42/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.3.42/linux/arch/sparc/kernel/irq.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/kernel/irq.c Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.100 2000/01/29 01:38:04 anton Exp $ +/* $Id: irq.c,v 1.101 2000/02/09 11:15:03 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -205,9 +205,6 @@ unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -atomic_t global_bh_lock = ATOMIC_INIT(0); -spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED; - /* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; @@ -217,9 +214,6 @@ /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); -/* This protects BH software state (masks, things like that). */ -spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED; - void smp_show_backtrace_all_cpus(void); void show_backtrace(void); @@ -239,7 +233,7 @@ } printk("]\n"); - printk("bh: %d [ ", (spin_is_locked(&global_bh_count) ? 1 : 0)); + printk("bh: %d [ ", (spin_is_locked(&global_bh_lock) ? 1 : 0)); for (i = 0; i < NR_CPUS; i++) { printk("%d ", local_bh_count[cpu]); @@ -253,18 +247,6 @@ #endif } -static inline void wait_on_bh(void) -{ - int count = MAXCOUNT; - do { - if(!--count) { - show("wait_on_bh"); - count = 0; - } - barrier(); - } while(spin_is_locked(&global_bh_count)); -} - /* * We have to allow irqs to arrive between __sti and __cli */ @@ -281,7 +263,7 @@ * already executing in one.. */ if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !spin_is_locked(&global_bh_count)) + if (local_bh_count[cpu] || !spin_is_locked(&global_bh_lock)) break; } @@ -300,26 +282,12 @@ continue; if (spin_is_locked (&global_irq_lock)) continue; - if (!local_bh_count[cpu] && spin_is_locked(&global_bh_count)) + if (!local_bh_count[cpu] && spin_is_locked(&global_bh_lock)) continue; if (spin_trylock(&global_irq_lock)) break; } } -} - -/* - * This is called when we want to synchronize with - * bottom half handlers. We need to wait until - * no other CPU is executing any bottom half handler. - * - * Don't wait if we're already running in an interrupt - * context or are inside a bh handler. - */ -void synchronize_bh(void) -{ - if (spin_is_locked (&global_bh_count) && !in_interrupt()) - wait_on_bh(); } /* diff -u --recursive --new-file v2.3.42/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S --- v2.3.42/linux/arch/sparc/kernel/rtrap.S Tue Jan 11 22:31:38 2000 +++ linux/arch/sparc/kernel/rtrap.S Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.53 2000/01/08 16:38:18 anton Exp $ +/* $Id: rtrap.S,v 1.54 2000/02/09 11:15:03 davem Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -48,16 +48,18 @@ .globl rtrap_patch3, rtrap_patch4, rtrap_patch5 .globl C_LABEL(ret_trap_lockless_ipi) ret_trap_entry: - sethi %hi(C_LABEL(bh_active)), %l3 - sethi %hi(C_LABEL(bh_mask)), %l4 - ld [%l4 + %lo(C_LABEL(bh_mask))], %g5 - ld [%l3 + %lo(C_LABEL(bh_active))], %g4 + ld [%curptr + AOFF_task_processor], %l3 + sll %l3, 5, %l3 + sethi %hi(C_LABEL(softirq_state)), %l4 + add %l4, %l3, %l4 + ld [%l4 + %lo(C_LABEL(softirq_state))], %g5 + ld [%l4 + %lo(C_LABEL(softirq_state) + 4)], %g4 andcc %g4, %g5, %g0 be C_LABEL(ret_trap_lockless_ipi) nop - call C_LABEL(do_bottom_half) + 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.3.42/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.3.42/linux/arch/sparc/kernel/sparc_ksyms.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/kernel/sparc_ksyms.c Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.88 2000/01/28 13:41:55 jj Exp $ +/* $Id: sparc_ksyms.c,v 1.89 2000/02/09 11:15:03 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -11,8 +11,10 @@ #include #include +#include #include #include +#include #include #include #include diff -u --recursive --new-file v2.3.42/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.3.42/linux/arch/sparc/kernel/sys_sparc.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/kernel/sys_sparc.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.59 2000/01/29 07:40:10 davem Exp $ +/* $Id: sys_sparc.c,v 1.60 2000/02/08 20:24:18 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.42/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c --- v2.3.42/linux/arch/sparc/kernel/time.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/kernel/time.c Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.51 2000/01/29 01:08:59 anton Exp $ +/* $Id: time.c,v 1.53 2000/02/09 21:11:04 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -429,12 +429,14 @@ extern __inline__ unsigned long do_gettimeoffset(void) { + struct tasklet_struct *t; unsigned long offset = 0; unsigned int count; count = (*master_l10_counter >> 10) & 0x1fffff; - if(test_bit(TIMER_BH, &bh_active)) + t = &bh_task_vec[TIMER_BH]; + if (test_bit(TASKLET_STATE_SCHED, &t->state)) offset = 1000000; return offset + count; diff -u --recursive --new-file v2.3.42/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.3.42/linux/arch/sparc/mm/init.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/mm/init.c Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.79 2000/01/29 01:09:06 anton Exp $ +/* $Id: init.c,v 1.80 2000/02/09 21:11:06 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -33,8 +33,6 @@ #include #include -extern void show_net_buffers(void); - unsigned long *sparc_valid_addr_bitmap; unsigned long phys_base; @@ -89,9 +87,6 @@ printk("%ld entries in page dir cache\n",pgd_cache_size); #endif show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } extern pgprot_t protection_map[16]; diff -u --recursive --new-file v2.3.42/linux/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c --- v2.3.42/linux/arch/sparc/mm/io-unit.c Fri Jan 21 18:19:16 2000 +++ linux/arch/sparc/mm/io-unit.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.20 2000/01/15 00:51:27 anton Exp $ +/* $Id: io-unit.c,v 1.21 2000/02/06 22:55:45 zaitcev Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -210,6 +210,20 @@ static void iounit_unmap_dma_area(unsigned long addr, int len) { + /* XXX Somebody please fill this in */ +} + +/* XXX We do not pass sbus device here, bad. */ +static unsigned long iounit_translate_dvma(unsigned long addr) +{ + struct sbus_bus *sbus = sbus_root; /* They are all the same */ + struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; + int i; + iopte_t *iopte; + + i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT); + iopte = (iopte_t *)(iounit->page_table + i); + return (iopte_val(*iopte) & 0xFFFFFFF0) << 4; /* XXX sun4d guru, help */ } #endif @@ -237,6 +251,7 @@ #ifdef CONFIG_SBUS BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM); #endif } diff -u --recursive --new-file v2.3.42/linux/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c --- v2.3.42/linux/arch/sparc/mm/iommu.c Fri Jan 21 18:19:16 2000 +++ linux/arch/sparc/mm/iommu.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: iommu.c,v 1.18 2000/01/15 00:51:27 anton Exp $ +/* $Id: iommu.c,v 1.19 2000/02/06 22:55:45 zaitcev Exp $ * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -289,8 +289,32 @@ iommu_invalidate(iommu->regs); } -static void iommu_unmap_dma_area(unsigned long addr, int len) +static void iommu_unmap_dma_area(unsigned long busa, int len) { + struct iommu_struct *iommu = sbus_root->iommu; + iopte_t *iopte = iommu->page_table; + unsigned long end; + + iopte += ((busa - iommu->start) >> PAGE_SHIFT); + end = PAGE_ALIGN((busa + len)); + while (busa < end) { + iopte_val(*iopte++) = 0; + busa += PAGE_SIZE; + } + flush_tlb_all(); /* P3: Hmm... it would not hurt. */ + iommu_invalidate(iommu->regs); +} + +static unsigned long iommu_translate_dvma(unsigned long busa) +{ + struct iommu_struct *iommu = sbus_root->iommu; + iopte_t *iopte = iommu->page_table; + unsigned long pa; + + iopte += ((busa - iommu->start) >> PAGE_SHIFT); + pa = pte_val(*iopte); + pa = (pa & 0xFFFFFFF0) << 4; /* Loose higher bits of 36 */ + return pa + PAGE_OFFSET; } #endif @@ -327,5 +351,6 @@ #ifdef CONFIG_SBUS BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_translate_dvma, iommu_translate_dvma, BTFIXUPCALL_NORM); #endif } diff -u --recursive --new-file v2.3.42/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c --- v2.3.42/linux/arch/sparc/mm/loadmmu.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/mm/loadmmu.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: loadmmu.c,v 1.54 2000/01/29 01:09:07 anton Exp $ +/* $Id: loadmmu.c,v 1.56 2000/02/08 20:24:21 davem Exp $ * loadmmu.c: This code loads up all the mm function pointers once the * machine type has been determined. It also sets the static * mmu values such as PAGE_NONE, etc. @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -27,6 +26,7 @@ extern void ld_mmu_sun4c(void); extern void ld_mmu_srmmu(void); +extern void ioport_init(void); void __init load_mmu(void) { @@ -44,4 +44,5 @@ prom_halt(); } btfixup(); + ioport_init(); } diff -u --recursive --new-file v2.3.42/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.3.42/linux/arch/sparc/mm/srmmu.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc/mm/srmmu.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.205 2000/01/21 17:59:46 anton Exp $ +/* $Id: srmmu.c,v 1.206 2000/02/08 07:45:59 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1304,7 +1304,7 @@ sparc_context_init(num_contexts); { - unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; zones_size[ZONE_DMA] = end_pfn; free_area_init(zones_size); diff -u --recursive --new-file v2.3.42/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.3.42/linux/arch/sparc/mm/sun4c.c Fri Jan 21 18:19:16 2000 +++ linux/arch/sparc/mm/sun4c.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.185 2000/01/15 00:51:32 anton Exp $ +/* $Id: sun4c.c,v 1.187 2000/02/08 07:46:01 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -584,15 +584,24 @@ } } -static void sun4c_unmap_dma_area(unsigned long addr, int len) +static unsigned long sun4c_translate_dvma(unsigned long busa) { + /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ + unsigned long pte = sun4c_get_pte(busa); + return (pte << PAGE_SHIFT) + PAGE_OFFSET; } -static void sun4c_inval_dma_area(unsigned long addr, int len) +static unsigned long sun4c_unmap_dma_area(unsigned long busa, int len) { + /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ + /* XXX Implement this */ } -static void sun4c_flush_dma_area(unsigned long addr, int len) +static void sun4c_inval_dma_area(unsigned long virt, int len) +{ +} + +static void sun4c_flush_dma_area(unsigned long virt, int len) { } @@ -2574,7 +2583,7 @@ sparc_context_init(num_contexts); { - unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; zones_size[ZONE_DMA] = end_pfn; free_area_init(zones_size); @@ -2721,6 +2730,7 @@ BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(mmu_flush_dma_area, sun4c_flush_dma_area, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(mmu_inval_dma_area, sun4c_inval_dma_area, BTFIXUPCALL_NORM); diff -u --recursive --new-file v2.3.42/linux/arch/sparc/prom/bootstr.c linux/arch/sparc/prom/bootstr.c --- v2.3.42/linux/arch/sparc/prom/bootstr.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/prom/bootstr.c Tue Feb 8 18:23:13 2000 @@ -1,10 +1,9 @@ -/* $Id: bootstr.c,v 1.19 2000/01/29 01:09:11 anton Exp $ +/* $Id: bootstr.c,v 1.20 2000/02/08 20:24:23 davem Exp $ * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) */ -#include #include #include #include diff -u --recursive --new-file v2.3.42/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c --- v2.3.42/linux/arch/sparc/prom/console.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/prom/console.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.21 2000/01/29 01:09:12 anton Exp $ +/* $Id: console.c,v 1.22 2000/02/08 20:24:23 davem Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * @@ -6,7 +6,6 @@ * Copyright (C) 1998 Pete Zaitcev */ -#include #include #include #include diff -u --recursive --new-file v2.3.42/linux/arch/sparc/prom/printf.c linux/arch/sparc/prom/printf.c --- v2.3.42/linux/arch/sparc/prom/printf.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/prom/printf.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: printf.c,v 1.6 2000/01/29 01:09:12 anton Exp $ +/* $Id: printf.c,v 1.7 2000/02/08 20:24:23 davem Exp $ * printf.c: Internal prom library printf facility. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -8,7 +8,6 @@ * about or use it! It's simple and smelly anyway.... */ -#include #include #include diff -u --recursive --new-file v2.3.42/linux/arch/sparc/vmlinux.lds linux/arch/sparc/vmlinux.lds --- v2.3.42/linux/arch/sparc/vmlinux.lds Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/vmlinux.lds Tue Feb 8 18:23:13 2000 @@ -73,4 +73,5 @@ .debug_pubnames 0 : { *(.debug_pubnames) } .debug_sfnames 0 : { *(.debug_sfnames) } .line 0 : { *(.line) } + /DISCARD/ : { *(.text.exit) *(.data.exit) } } diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.3.42/linux/arch/sparc64/config.in Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc64/config.in Thu Feb 10 12:16:38 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.89 2000/01/31 21:10:10 davem Exp $ +# $Id: config.in,v 1.95 2000/02/10 02:51:12 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -17,13 +17,6 @@ bool 'Symmetric multi-processing support' CONFIG_SMP -mainmenu_option next_comment -comment 'Console drivers' -bool 'PROM console' CONFIG_PROM_CONSOLE -bool 'Support Frame buffer devices' CONFIG_FB -source drivers/video/Config.in -endmenu - # Global things across all Sun machines. define_bool CONFIG_SBUS y define_bool CONFIG_SBUSCHAR y @@ -38,6 +31,14 @@ define_bool CONFIG_SUN_IO y bool 'PCI support' CONFIG_PCI source drivers/pci/Config.in + +mainmenu_option next_comment +comment 'Console drivers' +bool 'PROM console' CONFIG_PROM_CONSOLE +bool 'Support Frame buffer devices' CONFIG_FB +source drivers/video/Config.in +endmenu + source drivers/sbus/char/Config.in source drivers/sbus/audio/Config.in @@ -129,11 +130,24 @@ comment 'SCSI support type (disk, tape, CDrom)' dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + + if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then + int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 + fi + dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + + if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then + int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 + fi + dep_tristate ' SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 fi + dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' @@ -141,6 +155,7 @@ bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS + bool ' SCSI logging facility' CONFIG_SCSI_LOGGING mainmenu_option next_comment comment 'SCSI low-level drivers' @@ -198,26 +213,48 @@ bool ' Keepalive and linefill' CONFIG_SLIP_SMART bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 fi - bool ' Sun LANCE support' CONFIG_SUNLANCE - tristate ' Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL + + mainmenu_option next_comment + comment 'Ethernet (10 or 100Mbit)' + + bool 'Sun LANCE support' CONFIG_SUNLANCE + tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC + tristate 'Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC fi tristate ' Sun QuadEthernet support' CONFIG_SUNQE - tristate ' MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS if [ "$CONFIG_PCI" = "y" ]; then - tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 - tristate ' 3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX - tristate ' RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 - tristate ' PCI NE2000 support' CONFIG_NE2K_PCI - tristate ' EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 - tristate ' Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE + tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 + tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX + tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 + tristate 'PCI NE2000 support' CONFIG_NE2K_PCI + tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 + tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi + endmenu + + mainmenu_option next_comment + comment 'Ethernet (1000 Mbit)' + + if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC + if [ "$CONFIG_ACENIC" != "n" ]; then + bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I + fi + tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN + fi + tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS + endmenu + # bool ' FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then # fi + + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi fi -endmenu + endmenu fi # This one must be before the filesystem configs. -DaveM diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.42/linux/arch/sparc64/defconfig Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc64/defconfig Thu Feb 10 12:16:38 2000 @@ -13,6 +13,19 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y # CONFIG_SMP is not set +CONFIG_SBUS=y +CONFIG_SBUSCHAR=y +CONFIG_BUSMOUSE=y +CONFIG_SUN_MOUSE=y +CONFIG_SERIAL=y +CONFIG_SUN_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SUN_KEYBOARD=y +CONFIG_SUN_CONSOLE=y +CONFIG_SUN_AUXIO=y +CONFIG_SUN_IO=y +CONFIG_PCI=y +CONFIG_PCI_NAMES=y # # Console drivers @@ -51,19 +64,6 @@ CONFIG_FBCON_FONTWIDTH8_ONLY=y CONFIG_FONT_SUN8x16=y # CONFIG_FBCON_FONTS is not set -CONFIG_SBUS=y -CONFIG_SBUSCHAR=y -CONFIG_BUSMOUSE=y -CONFIG_SUN_MOUSE=y -CONFIG_SERIAL=y -CONFIG_SUN_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -CONFIG_SUN_KEYBOARD=y -CONFIG_SUN_CONSOLE=y -CONFIG_SUN_AUXIO=y -CONFIG_SUN_IO=y -CONFIG_PCI=y -CONFIG_PCI_NAMES=y # # Misc Linux/SPARC drivers @@ -75,10 +75,6 @@ # CONFIG_SUN_BPP is not set # CONFIG_SUN_VIDEOPIX is not set CONFIG_SUN_AURORA=m -# CONFIG_TADPOLE_TS102_UCTRL is not set -# CONFIG_SUN_JSFLASH is not set -CONFIG_APM_RTC_IS_GMT=y -# CONFIG_RTC is not set # # Linux/SPARC audio subsystem (EXPERIMENTAL) @@ -203,9 +199,12 @@ # SCSI support type (disk, tape, CDrom) # CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=m # @@ -213,6 +212,7 @@ # CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers @@ -263,11 +263,14 @@ CONFIG_SLIP_COMPRESSED=y CONFIG_SLIP_SMART=y # CONFIG_SLIP_MODE_SLIP6 is not set + +# +# Ethernet (10 or 100Mbit) +# CONFIG_SUNLANCE=y CONFIG_HAPPYMEAL=y CONFIG_SUNBMAC=m CONFIG_SUNQE=m -CONFIG_MYRI_SBUS=m CONFIG_DE4X5=m CONFIG_VORTEX=m CONFIG_RTL8139=m @@ -276,6 +279,14 @@ CONFIG_ADAPTEC_STARFIRE=m # +# Ethernet (1000 Mbit) +# +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set +CONFIG_SK98LIN=m +CONFIG_MYRI_SBUS=m + +# # Unix 98 PTY support # CONFIG_UNIX98_PTYS=y @@ -297,7 +308,6 @@ CONFIG_AFFS_FS=m # CONFIG_HFS_FS is not set CONFIG_BFS_FS=m -# CONFIG_BFS_FS_WRITE is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.3.42/linux/arch/sparc64/kernel/Makefile Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/kernel/Makefile Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.50 1999/12/21 04:02:24 davem Exp $ +# $Id: Makefile,v 1.51 2000/02/08 05:11:31 jj Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -19,13 +19,13 @@ O_OBJS := process.o setup.o cpu.o idprom.o \ traps.o devices.o auxio.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ - unaligned.o central.o pci.o pci_common.o pci_iommu.o \ - pci_psycho.o pci_sabre.o starfire.o semaphore.o \ + unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o OX_OBJS := sparc64_ksyms.o ifdef CONFIG_PCI - O_OBJS += ebus.o + O_OBJS += ebus.o pci_common.o pci_iommu.o \ + pci_psycho.o pci_sabre.o endif ifdef CONFIG_SUNOS_EMUL diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.3.42/linux/arch/sparc64/kernel/ioctl32.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.76 2000/01/31 21:10:15 davem Exp $ +/* $Id: ioctl32.c,v 1.79 2000/02/08 20:24:25 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -17,7 +17,9 @@ #include #include #include +#if 0 /* New RAID code is half-merged... -DaveM */ #include +#endif #include #include #include @@ -61,6 +63,18 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + /* Use this to get at 32-bit user passed pointers. See sys_sparc32.c for description about these. */ #define A(__x) ((unsigned long)(__x)) @@ -1753,6 +1767,217 @@ return err; } +struct atmif_sioc32 { + int number; + int length; + __kernel_caddr_t32 arg; +}; + +struct atm_iobuf32 { + int length; + __kernel_caddr_t32 buffer; +}; + +#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) +#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32) +#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) +#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) +#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) +#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32) +#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32) +#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32) +#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32) +#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32) +#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32) +#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) +#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) +#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} atm_ioctl_map[] = { + { ATM_GETLINKRATE32, ATM_GETLINKRATE }, + { ATM_GETNAMES32, ATM_GETNAMES }, + { ATM_GETTYPE32, ATM_GETTYPE }, + { ATM_GETESI32, ATM_GETESI }, + { ATM_GETADDR32, ATM_GETADDR }, + { ATM_RSTADDR32, ATM_RSTADDR }, + { ATM_ADDADDR32, ATM_ADDADDR }, + { ATM_DELADDR32, ATM_DELADDR }, + { ATM_GETCIRANGE32, ATM_GETCIRANGE }, + { ATM_SETCIRANGE32, ATM_SETCIRANGE }, + { ATM_SETESI32, ATM_SETESI }, + { ATM_SETESIF32, ATM_SETESIF }, + { ATM_GETSTAT32, ATM_GETSTAT }, + { ATM_GETSTATZ32, ATM_GETSTATZ } +}; + +#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0])) + + +static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct atm_iobuf32 iobuf32; + struct atm_iobuf iobuf = { 0, NULL }; + mm_segment_t old_fs; + int err; + + err = copy_from_user(&iobuf32, (struct atm_iobuf32*)arg, + sizeof(struct atm_iobuf32)); + if (err) + return -EFAULT; + + iobuf.length = iobuf32.length; + + if (iobuf32.buffer == (__kernel_caddr_t32) NULL || iobuf32.length == 0) { + iobuf.buffer = (void*)(unsigned long)iobuf32.buffer; + } else { + iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL); + if (iobuf.buffer == NULL) { + err = -ENOMEM; + goto out; + } + + err = copy_from_user(iobuf.buffer, A(iobuf32.buffer), iobuf.length); + if (err) { + err = -EFAULT; + goto out; + } + } + + old_fs = get_fs(); set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&iobuf); + set_fs (old_fs); + if(err) + goto out; + + if(iobuf.buffer && iobuf.length > 0) { + err = copy_to_user(A(iobuf32.buffer), iobuf.buffer, iobuf.length); + if (err) { + err = -EFAULT; + goto out; + } + } + err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length)); + + out: + if(iobuf32.buffer && iobuf32.length > 0) + kfree(iobuf.buffer); + + return err; +} + + +static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct atmif_sioc32 sioc32; + struct atmif_sioc sioc = { 0, 0, NULL }; + mm_segment_t old_fs; + int err; + + err = copy_from_user(&sioc32, (struct atmif_sioc32*)arg, + sizeof(struct atmif_sioc32)); + if (err) + return -EFAULT; + + sioc.number = sioc32.number; + sioc.length = sioc32.length; + + if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc32.length == 0) { + sioc.arg = (void*)(unsigned long)sioc32.arg; + } else { + sioc.arg = kmalloc(sioc.length, GFP_KERNEL); + if (sioc.arg == NULL) { + err = -ENOMEM; + goto out; + } + + err = copy_from_user(sioc.arg, A(sioc32.arg), sioc32.length); + if (err) { + err = -EFAULT; + goto out; + } + } + + old_fs = get_fs(); set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&sioc); + set_fs (old_fs); + if(err) { + goto out; + } + + if(sioc.arg && sioc.length > 0) { + err = copy_to_user(A(sioc32.arg), sioc.arg, sioc.length); + if (err) { + err = -EFAULT; + goto out; + } + } + err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length)); + + out: + if(sioc32.arg && sioc32.length > 0) + kfree(sioc.arg); + + return err; +} + + +static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) +{ + int i; + unsigned int cmd = 0; + + switch (cmd32) { + case SUNI_GETLOOP: + case SUNI_SETLOOP: + case SONET_GETSTAT: + case SONET_GETSTATZ: + case SONET_GETDIAG: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + case SONET_GETFRAMING: + case SONET_GETFRSENSE: + return do_atmif_sioc(fd, cmd32, arg); + } + + if (cmd == 0) { + for (i = 0; i < NR_ATM_IOCTL; i++) { + if (cmd32 == atm_ioctl_map[i].cmd32) { + cmd = atm_ioctl_map[i].cmd; + break; + } + } + if (i == NR_ATM_IOCTL) { + return -EINVAL; + } + } + + switch (cmd) { + case ATM_GETNAMES: + return do_atm_iobuf(fd, cmd, arg); + + case ATM_GETLINKRATE: + case ATM_GETTYPE: + case ATM_GETESI: + case ATM_GETADDR: + case ATM_RSTADDR: + case ATM_ADDADDR: + case ATM_DELADDR: + case ATM_GETCIRANGE: + case ATM_SETCIRANGE: + case ATM_SETESI: + case ATM_SETESIF: + case ATM_GETSTAT: + case ATM_GETSTATZ: + return do_atmif_sioc(fd, cmd, arg); + } + + return -EINVAL; +} + asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; @@ -1945,6 +2170,33 @@ error = do_smb_getmountuid(fd, cmd, arg); goto out; + case ATM_GETLINKRATE32: + case ATM_GETNAMES32: + case ATM_GETTYPE32: + case ATM_GETESI32: + case ATM_GETADDR32: + case ATM_RSTADDR32: + case ATM_ADDADDR32: + case ATM_DELADDR32: + case ATM_GETCIRANGE32: + case ATM_SETCIRANGE32: + case ATM_SETESI32: + case ATM_SETESIF32: + case ATM_GETSTAT32: + case ATM_GETSTATZ32: + case SUNI_GETLOOP: + case SUNI_SETLOOP: + case SONET_GETSTAT: + case SONET_GETSTATZ: + case SONET_GETDIAG: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + case SONET_GETFRAMING: + case SONET_GETFRSENSE: + error = do_atm_ioctl(fd, cmd, arg); + goto out; + /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ @@ -2062,12 +2314,16 @@ case BLKRRPART: case BLKFLSBUF: case BLKRASET: - + +#if 0 /* New RAID code is being merged, fix up to handle + * new RAID ioctls when fully merged in 2.3.x -DaveM + */ /* 0x09 */ case REGISTER_DEV: case REGISTER_DEV_NEW: case START_MD: case STOP_MD: +#endif /* Big K */ case PIO_FONT: @@ -2454,6 +2710,23 @@ /* SMB ioctls which do not need any translations */ case SMB_IOC_NEWCONN: + /* Little a */ + case ATMSIGD_CTRL: + case ATMARPD_CTRL: + case ATMLEC_CTRL: + case ATMLEC_MCAST: + case ATMLEC_DATA: + case ATM_SETSC: + case SIOCSIFATMTCP: + case SIOCMKCLIP: + case ATMARP_MKIP: + case ATMARP_SETENTRY: + case ATMARP_ENCAP: + case ATMTCP_CREATE: + case ATMTCP_REMOVE: + case ATMMPC_CTRL: + case ATMMPC_DATA: + error = sys_ioctl (fd, cmd, arg); goto out; diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.3.42/linux/arch/sparc64/kernel/irq.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc64/kernel/irq.c Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.81 2000/01/21 06:33:59 davem Exp $ +/* $Id: irq.c,v 1.82 2000/02/09 11:15:07 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include /* XXX ADD add_foo_randomness() calls... -DaveM */ @@ -546,8 +547,6 @@ #define irq_enter(cpu, irq) (local_irq_count++) #define irq_exit(cpu, irq) (local_irq_count--) #else -atomic_t global_bh_lock = ATOMIC_INIT(0); -spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED; /* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; @@ -573,24 +572,12 @@ atomic_read(&global_irq_count), cpu_data[0].irq_count, cpu_data[1].irq_count); printk("bh: %d [%u %u]\n", - (spin_is_locked(&global_bh_count) ? 1 : 0), + (spin_is_locked(&global_bh_lock) ? 1 : 0), cpu_data[0].bh_count, cpu_data[1].bh_count); } #define MAXCOUNT 100000000 -static inline void wait_on_bh(void) -{ - int count = MAXCOUNT; - do { - if(!--count) { - show("wait_on_bh"); - count = 0; - } - membar("#LoadLoad"); - } while(spin_is_locked(&global_bh_count)); -} - #define SYNC_OTHER_ULTRAS(x) udelay(x+1) static inline void wait_on_irq(int cpu) @@ -599,7 +586,7 @@ for(;;) { membar("#LoadLoad"); if (!atomic_read (&global_irq_count)) { - if (local_bh_count || ! spin_is_locked(&global_bh_count)) + if (local_bh_count || ! spin_is_locked(&global_bh_lock)) break; } spin_unlock (&global_irq_lock); @@ -616,18 +603,12 @@ continue; if (spin_is_locked (&global_irq_lock)) continue; - if (!local_bh_count && spin_is_locked (&global_bh_count)) + if (!local_bh_count && spin_is_locked (&global_bh_lock)) continue; if (spin_trylock(&global_irq_lock)) break; } } -} - -void synchronize_bh(void) -{ - if (spin_is_locked (&global_bh_count) && !in_interrupt()) - wait_on_bh(); } void synchronize_irq(void) diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.3.42/linux/arch/sparc64/kernel/pci.c Fri Jan 21 18:19:16 2000 +++ linux/arch/sparc64/kernel/pci.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.14 2000/01/13 00:05:43 davem Exp $ +/* $Id: pci.c,v 1.15 2000/02/08 05:11:29 jj Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -19,11 +19,6 @@ #include #include #include - -#ifndef NEW_PCI_DMA_MAP -unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; -unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; -#endif unsigned long pci_memspace_mask = 0xffffffffUL; diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/pci_impl.h linux/arch/sparc64/kernel/pci_impl.h --- v2.3.42/linux/arch/sparc64/kernel/pci_impl.h Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/kernel/pci_impl.h Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_impl.h,v 1.4 1999/12/17 12:32:03 jj Exp $ +/* $Id: pci_impl.h,v 1.5 2000/02/08 05:11:32 jj Exp $ * pci_impl.h: Helper definitions for PCI controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -33,21 +33,6 @@ extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); - -#ifndef NEW_PCI_DMA_MAP -/* IOMMU/DVMA initialization. */ -#define PCI_DVMA_HASH_NONE ~0UL -static __inline__ void set_dvma_hash(unsigned long dvma_offset, - unsigned long paddr, - unsigned long daddr) -{ - unsigned long dvma_addr = dvma_offset + daddr; - unsigned long vaddr = (unsigned long)__va(paddr); - - pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr; - pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr; -} -#endif /* Configuration space access. */ extern spinlock_t pci_poke_lock; diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c --- v2.3.42/linux/arch/sparc64/kernel/pci_psycho.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc64/kernel/pci_psycho.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.10 2000/01/28 13:42:00 jj Exp $ +/* $Id: pci_psycho.c,v 1.11 2000/02/08 05:11:32 jj Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1219,12 +1219,6 @@ static void __init psycho_iommu_init(struct pci_controller_info *p) { -#ifndef NEW_PCI_DMA_MAP - struct linux_mlist_p1275 *mlist; - unsigned long n; - iopte_t *iopte; - int tsbsize = 32; -#endif extern int this_is_starfire; extern void *starfire_hookup(int); unsigned long tsbbase, i; @@ -1258,19 +1252,11 @@ control &= ~(PSYCHO_IOMMU_CTRL_DENAB); psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); -#ifndef NEW_PCI_DMA_MAP - /* Using assumed page size 64K with 32K entries we need 256KB iommu page - * table (32K ioptes * 8 bytes per iopte). This is - * page order 5 on UltraSparc. - */ - tsbbase = __get_free_pages(GFP_KERNEL, 5); -#else /* Using assumed page size 8K with 128K entries we need 1MB iommu page * table (128K ioptes * 8 bytes per iopte). This is * page order 7 on UltraSparc. */ tsbbase = __get_free_pages(GFP_KERNEL, 7); -#endif if (!tsbbase) { prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n"); prom_halt(); @@ -1278,112 +1264,17 @@ p->iommu.page_table = (iopte_t *)tsbbase; p->iommu.page_table_sz_bits = 17; p->iommu.page_table_map_base = 0xc0000000; -#ifndef NEW_PCI_DMA_MAP - memset((char *)tsbbase, 0, PAGE_SIZE << 5); -#else memset((char *)tsbbase, 0, PAGE_SIZE << 7); -#endif /* Make sure DMA address 0 is never returned just to allow catching of buggy drivers. */ p->iommu.lowest_free[0] = 1; -#ifndef NEW_PCI_DMA_MAP - iopte = (iopte_t *)tsbbase; - /* Initialize to "none" settings. */ - for(i = 0; i < PCI_DVMA_HASHSZ; i++) { - pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; - pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; - } - - n = 0; - mlist = *prom_meminfo()->p1275_totphys; - while (mlist) { - unsigned long paddr = mlist->start_adr; - unsigned long num_bytes = mlist->num_bytes; - - if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) - goto next; - - if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) - num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr; - - /* Align base and length so we map whole hash table sized chunks - * at a time (and therefore full 64K IOMMU pages). - */ - paddr &= ~((1UL << 24UL) - 1); - num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); - - /* Move up the base for mappings already created. */ - while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != - PCI_DVMA_HASH_NONE) { - paddr += (1UL << 24UL); - num_bytes -= (1UL << 24UL); - if(num_bytes == 0UL) - goto next; - } - - /* Move down the size for tail mappings already created. */ - while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != - PCI_DVMA_HASH_NONE) { - num_bytes -= (1UL << 24UL); - if(num_bytes == 0UL) - goto next; - } - - /* Now map the rest. */ - for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { - iopte_val(*iopte) = ((IOPTE_VALID | IOPTE_64K | - IOPTE_CACHE | IOPTE_WRITE) | - (paddr & IOPTE_PAGE)); - - if (!(n & 0xff)) - set_dvma_hash(0x80000000, paddr, (n << 16)); - - if (++n > (tsbsize * 1024)) - goto out; - - paddr += (1 << 16); - iopte++; - } - next: - mlist = mlist->theres_more; - } -out: - if (mlist) { - prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); - prom_printf("Try booting with mem=xxxM or similar\n"); - prom_halt(); - } -#endif psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase)); control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL); -#ifndef NEW_PCI_DMA_MAP - control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ); - control |= (PSYCHO_IOMMU_CTRL_TBWSZ | PSYCHO_IOMMU_CTRL_ENAB); - switch(tsbsize) { - case 8: - p->iommu.page_table_map_base = 0xe0000000; - control |= PSYCHO_IOMMU_TSBSZ_8K; - break; - case 16: - p->iommu.page_table_map_base = 0xc0000000; - control |= PSYCHO_IOMMU_TSBSZ_16K; - break; - case 32: - p->iommu.page_table_map_base = 0x80000000; - control |= PSYCHO_IOMMU_TSBSZ_32K; - break; - default: - prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); - prom_halt(); - break; - } -#else control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ); control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB); -#endif psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); /* If necessary, hook us up for starfire IRQ translations. */ diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c --- v2.3.42/linux/arch/sparc64/kernel/pci_sabre.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc64/kernel/pci_sabre.c Tue Feb 8 18:23:13 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.11 2000/01/28 13:42:01 jj Exp $ +/* $Id: pci_sabre.c,v 1.12 2000/02/08 05:11:33 jj Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1107,11 +1107,6 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize, unsigned long dvma_offset) { -#ifndef NEW_PCI_DMA_MAP - struct linux_mlist_p1275 *mlist; - unsigned long n; - iopte_t *iopte; -#endif unsigned long tsbbase, i, order; u64 control; @@ -1154,99 +1149,9 @@ of buggy drivers. */ p->iommu.lowest_free[0] = 1; -#ifndef NEW_PCI_DMA_MAP - iopte = (iopte_t *)tsbbase; - - /* Initialize to "none" settings. */ - for(i = 0; i < PCI_DVMA_HASHSZ; i++) { - pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; - pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; - } - - n = 0; - mlist = *prom_meminfo()->p1275_totphys; - while (mlist) { - unsigned long paddr = mlist->start_adr; - unsigned long num_bytes = mlist->num_bytes; - - if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) - goto next; - - if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) - num_bytes = - (((unsigned long) high_memory) - - PAGE_OFFSET) - paddr; - - /* Align base and length so we map whole hash table sized chunks - * at a time (and therefore full 64K IOMMU pages). - */ - paddr &= ~((1UL << 24UL) - 1); - num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); - - /* Move up the base for mappings already created. */ - while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != - PCI_DVMA_HASH_NONE) { - paddr += (1UL << 24UL); - num_bytes -= (1UL << 24UL); - if(num_bytes == 0UL) - goto next; - } - - /* Move down the size for tail mappings already created. */ - while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != - PCI_DVMA_HASH_NONE) { - num_bytes -= (1UL << 24UL); - if(num_bytes == 0UL) - goto next; - } - - /* Now map the rest. */ - for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { - iopte_val(*iopte) = ((IOPTE_VALID | IOPTE_64K | - IOPTE_CACHE | IOPTE_WRITE) | - (paddr & IOPTE_PAGE)); - - if (!(n & 0xff)) - set_dvma_hash(dvma_offset, paddr, (n << 16)); - if (++n > (tsbsize * 1024)) - goto out; - - paddr += (1 << 16); - iopte++; - } - next: - mlist = mlist->theres_more; - } -out: - if (mlist) { - prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); - prom_printf("Try booting with mem=xxxM or similar\n"); - prom_halt(); - } -#endif - sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); -#ifndef NEW_PCI_DMA_MAP - control &= ~(SABRE_IOMMUCTRL_TSBSZ); - control |= (SABRE_IOMMUCTRL_TBWSZ | SABRE_IOMMUCTRL_ENAB); - switch(tsbsize) { - case 8: - control |= SABRE_IOMMU_TSBSZ_8K; - break; - case 16: - control |= SABRE_IOMMU_TSBSZ_16K; - break; - case 32: - control |= SABRE_IOMMU_TSBSZ_32K; - break; - default: - prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); - prom_halt(); - break; - } -#else control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ); control |= SABRE_IOMMUCTRL_ENAB; switch(tsbsize) { @@ -1263,7 +1168,6 @@ prom_halt(); break; } -#endif sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); } @@ -1472,17 +1376,6 @@ } switch(vdma[1]) { -#ifndef NEW_PCI_DMA_MAP - case 0x20000000: - tsbsize = 8; - break; - case 0x40000000: - tsbsize = 16; - break; - case 0x80000000: - tsbsize = 32; - break; -#else case 0x20000000: tsbsize = 64; break; @@ -1490,7 +1383,6 @@ case 0x80000000: tsbsize = 128; break; -#endif default: prom_printf("SABRE: strange virtual-dma size.\n"); prom_halt(); diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.3.42/linux/arch/sparc64/kernel/rtrap.S Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/kernel/rtrap.S Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.47 1999/07/30 09:35:23 davem Exp $ +/* $Id: rtrap.S,v 1.48 2000/02/09 11:15:07 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -20,15 +20,17 @@ .globl rtrap_clr_l6, rtrap rtrap_clr_l6: clr %l6 /* Fall through */ -rtrap: sethi %hi(bh_active), %l2 - sethi %hi(bh_mask), %l1 - ldx [%l2 + %lo(bh_active)], %l4 - ldx [%l1 + %lo(bh_mask)], %l7 +rtrap: lduw [%g6 + AOFF_task_processor], %l0 + sethi %hi(softirq_state), %l2 + or %l2, %lo(softirq_state), %l2 + sllx %l0, 6, %l0 + ldx [%l2 + %l0], %l1 + srlx %l1, 32, %l2 - andcc %l4, %l7, %g0 - be,pt %xcc, 2f + andcc %l1, %l2, %g0 + be,pt %icc, 2f nop - call do_bottom_half + call do_softirq nop 2: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 sethi %hi(0xf << 20), %l4 diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.3.42/linux/arch/sparc64/kernel/sparc64_ksyms.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.72 2000/01/28 13:41:59 jj Exp $ +/* $Id: sparc64_ksyms.c,v 1.74 2000/02/09 11:15:07 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -127,11 +127,6 @@ /* Kernel wide locking */ EXPORT_SYMBOL(kernel_flag); -/* Software-IRQ BH locking */ -EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(global_bh_count); -EXPORT_SYMBOL(synchronize_bh); - /* Hard IRQ locking */ EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(global_irq_lock); @@ -160,8 +155,8 @@ #endif #else -EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(local_bh_count); +EXPORT_SYMBOL(local_irq_count); #endif /* rw semaphores */ @@ -194,12 +189,8 @@ EXPORT_SYMBOL(sbus_dma_sync_single); EXPORT_SYMBOL(sbus_dma_sync_sg); #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI EXPORT_SYMBOL(ebus_chain); -#ifndef NEW_PCI_DMA_MAP -EXPORT_SYMBOL(pci_dvma_v2p_hash); -EXPORT_SYMBOL(pci_dvma_p2v_hash); -#endif EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(outsb); @@ -208,8 +199,6 @@ EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); EXPORT_SYMBOL(insl); -#endif -#ifdef NEW_PCI_DMA_MAP EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.3.42/linux/arch/sparc64/mm/init.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc64/mm/init.c Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.144 2000/01/23 07:16:11 davem Exp $ +/* $Id: init.c,v 1.146 2000/02/09 21:11:09 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -30,7 +30,6 @@ #include #include -extern void show_net_buffers(void); extern void device_scan(void); struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; @@ -130,9 +129,6 @@ printk("%d entries in page dir cache\n",pgd_cache_size); #endif show_buffers(); -#ifdef CONFIG_NET - show_net_buffers(); -#endif } int mmu_info(char *buf) @@ -926,7 +922,7 @@ flush_tlb_all(); { - unsigned int zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; zones_size[ZONE_DMA] = end_pfn; free_area_init(zones_size); diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c --- v2.3.42/linux/arch/sparc64/solaris/socksys.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc64/solaris/socksys.c Wed Feb 9 19:39:04 2000 @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.10 1999/08/31 06:55:08 davem Exp $ +/* $Id: socksys.c,v 1.11 2000/02/09 22:32:17 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -48,16 +48,7 @@ static unsigned int (*sock_poll)(struct file *, poll_table *); static struct file_operations socksys_file_ops = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* open */ - NULL, /* flush */ - NULL, /* release */ + /* Currently empty */ }; static int socksys_open(struct inode * inode, struct file * filp) @@ -162,16 +153,8 @@ } static struct file_operations socksys_fops = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - socksys_open, /* open */ - NULL, /* flush */ - socksys_release,/* release */ + open: socksys_open, + release: socksys_release, }; int __init diff -u --recursive --new-file v2.3.42/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds --- v2.3.42/linux/arch/sparc64/vmlinux.lds Fri Aug 6 11:58:00 1999 +++ linux/arch/sparc64/vmlinux.lds Tue Feb 8 18:23:13 2000 @@ -74,4 +74,5 @@ .debug_pubnames 0 : { *(.debug_pubnames) } .debug_sfnames 0 : { *(.debug_sfnames) } .line 0 : { *(.line) } + /DISCARD/ : { *(.text.exit) *(.data.exit) } } diff -u --recursive --new-file v2.3.42/linux/drivers/acorn/char/Makefile linux/drivers/acorn/char/Makefile --- v2.3.42/linux/drivers/acorn/char/Makefile Tue Dec 14 01:27:23 1999 +++ linux/drivers/acorn/char/Makefile Sun Feb 6 17:45:25 2000 @@ -11,19 +11,17 @@ O_TARGET := acorn-char.o M_OBJS := -O_OBJS := +O_OBJS := i2c.o pcf8583.o O_OBJS_arc := keyb_arc.o O_OBJS_a5k := keyb_arc.o O_OBJS_rpc := keyb_ps2.o -ifeq ($(MACHINE),rpc) - ifeq ($(CONFIG_BUSMOUSE),y) - OX_OBJS += mouse_rpc.o - else - ifeq ($(CONFIG_BUSMOUSE),m) - MX_OBJS += mouse_rpc.o - endif +ifeq ($(CONFIG_RPCMOUSE),y) + OX_OBJS += mouse_rpc.o +else + ifeq ($(CONFIG_RPCSMOUSE),m) + MX_OBJS += mouse_rpc.o endif endif diff -u --recursive --new-file v2.3.42/linux/drivers/acorn/char/i2c.c linux/drivers/acorn/char/i2c.c --- v2.3.42/linux/drivers/acorn/char/i2c.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/char/i2c.c Sun Feb 6 17:45:25 2000 @@ -0,0 +1,203 @@ +/* + * linux/drivers/acorn/char/i2c.c + * + * Copyright (C) 2000 Russell King + * + * ARM IOC/IOMD i2c driver. + * + * On Acorn machines, the following i2c devices are on the bus: + * - PCF8583 real time clock & static RAM + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pcf8583.h" + +extern unsigned long +mktime(unsigned int year, unsigned int mon, unsigned int day, + unsigned int hour, unsigned int min, unsigned int sec); +extern int (*set_rtc)(void); + +static struct i2c_client *rtc_client; + +static inline int rtc_command(int cmd, void *data) +{ + int ret = -EIO; + + if (rtc_client) + ret = rtc_client->driver->command(rtc_client, cmd, data); + + return ret; +} + +/* + * Read the current RTC time and date, and update xtime. + */ +static void get_rtc_time(void) +{ + unsigned char ctrl; + unsigned char year; + struct rtc_tm rtctm; + struct mem rtcmem = { 0xc0, 1, &year }; + + /* + * Ensure that the RTC is running. + */ + rtc_command(RTC_GETCTRL, &ctrl); + if (ctrl & 0xc0) { + unsigned char new_ctrl; + + new_ctrl = ctrl & ~0xc0; + + printk("RTC: resetting control %02X -> %02X\n", + ctrl, new_ctrl); + + rtc_command(RTC_SETCTRL, &new_ctrl); + } + + /* + * Acorn machines store the year in + * the static RAM at location 192. + */ + if (rtc_command(MEM_READ, &rtcmem)) + return; + + if (rtc_command(RTC_GETDATETIME, &rtctm)) + return; + + if (year < 70) + year += 100; + + xtime.tv_usec = rtctm.cs * 10000; + xtime.tv_sec = mktime(1900 + year, rtctm.mon, rtctm.mday, + rtctm.hours, rtctm.mins, rtctm.secs); +} + +/* + * Set the RTC time only. Note that + * we do not touch the date. + */ +static int set_rtc_time(void) +{ + struct rtc_tm new_rtctm, old_rtctm; + unsigned long nowtime = xtime.tv_sec; + + if (rtc_command(RTC_GETDATETIME, &old_rtctm)) + return 0; + + new_rtctm.cs = xtime.tv_usec / 10000; + new_rtctm.secs = nowtime % 60; nowtime /= 60; + new_rtctm.mins = nowtime % 60; nowtime /= 60; + new_rtctm.hours = nowtime % 24; + + /* + * avoid writing when we're going to change the day + * of the month. We will retry in the next minute. + * This basically means that if the RTC must not drift + * by more than 1 minute in 11 minutes. + * + * [ rtc: 1/1/2000 23:58:00, real 2/1/2000 00:01:00, + * rtc gets set to 1/1/2000 00:01:00 ] + */ + if ((old_rtctm.hours == 23 && old_rtctm.mins == 59) || + (new_rtctm.hours == 23 && new_rtctm.mins == 59)) + return 1; + + return rtc_command(RTC_SETTIME, &new_rtctm); +} + + +#define FORCE_ONES 0xdc +#define SCL 0x02 +#define SDA 0x01 + +static int ioc_control; + +static void ioc_setscl(void *data, int state) +{ + if (state) + ioc_control |= SCL; + else + ioc_control &= ~SCL; + outb(ioc_control, IOC_CONTROL); +} + +static void ioc_setsda(void *data, int state) +{ + if (state) + ioc_control |= SDA; + else + ioc_control &= ~SDA; + outb(ioc_control, IOC_CONTROL); +} + +static int ioc_getscl(void *data) +{ + return (inb(IOC_CONTROL) & SCL) != 0; +} + +static int ioc_getsda(void *data) +{ + return (inb(IOC_CONTROL) & SDA) != 0; +} + +static struct i2c_algo_bit_data ioc_data = { + NULL, + ioc_setsda, + ioc_setscl, + ioc_getsda, + ioc_getscl, + 80, 80, 100 +}; + +static int ioc_client_reg(struct i2c_client *client) +{ + if (client->id == I2C_DRIVERID_PCF8583 && + client->addr == 0x50) { + rtc_client = client; + get_rtc_time(); + set_rtc = set_rtc_time; + } + + return 0; +} + +static int ioc_client_unreg(struct i2c_client *client) +{ + if (client == rtc_client) { + set_rtc = NULL; + rtc_client = NULL; + } + + return 0; +} + +static struct i2c_adapter ioc_ops = { + "IOC/IOMD", + I2C_HW_B_IOC, + NULL, + &ioc_data, + NULL, + NULL, + ioc_client_reg, + ioc_client_unreg +}; + +static int __init i2c_ioc_init(void) +{ + ioc_control = inb(IOC_CONTROL) | FORCE_ONES; + + ioc_setscl(NULL, 1); + ioc_setsda(NULL, 1); + + return i2c_bit_add_bus(&ioc_ops); +} + +__initcall(i2c_ioc_init); diff -u --recursive --new-file v2.3.42/linux/drivers/acorn/char/pcf8583.c linux/drivers/acorn/char/pcf8583.c --- v2.3.42/linux/drivers/acorn/char/pcf8583.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/char/pcf8583.c Sun Feb 6 17:45:25 2000 @@ -0,0 +1,232 @@ +/* + * linux/drivers/i2c/pcf8583.c + * + * Copyright (C) 2000 Russell King + * + * Driver for PCF8583 RTC & RAM chip + */ + +#include +#include +#include +#include +#include + +#include "pcf8583.h" + +static struct i2c_driver pcf8583_driver; + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { 0x50, 0x51, I2C_CLIENT_END }; + +static struct i2c_client_address_data addr_data = { + force: ignore, + ignore: ignore, + ignore_range: ignore, + normal_i2c: ignore, + normal_i2c_range: normal_addr, + probe: ignore, + probe_range: ignore +}; + +#define DAT(x) ((unsigned int)(x->data)) + +static int +pcf8583_attach(struct i2c_adapter *adap, int addr, unsigned short flags, + int kind) +{ + struct i2c_client *c; + unsigned char buf[1], ad[1] = { 0 }; + struct i2c_msg msgs[2] = { + { addr, 0, 1, ad }, + { addr, I2C_M_RD, 1, buf } + }; + + c = kmalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return -ENOMEM; + + strcpy(c->name, "PCF8583"); + c->id = pcf8583_driver.id; + c->flags = 0; + c->addr = addr; + c->adapter = adap; + c->driver = &pcf8583_driver; + c->data = NULL; + + if (i2c_transfer(c->adapter, msgs, 2) == 2) + DAT(c) = buf[0]; + + return i2c_attach_client(c); +} + +static int +pcf8583_probe(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, pcf8583_attach); +} + +static int +pcf8583_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + return 0; +} + +static int +pcf8583_get_datetime(struct i2c_client *client, struct rtc_tm *dt) +{ + unsigned char buf[8], addr[1] = { 1 }; + struct i2c_msg msgs[2] = { + { client->addr, 0, 1, addr }, + { client->addr, I2C_M_RD, 6, buf } + }; + int ret = -EIO; + + if (i2c_transfer(client->adapter, msgs, 2) == 2) { + dt->year_off = buf[4] >> 6; + dt->wday = buf[5] >> 5; + + buf[4] &= 0x3f; + buf[5] &= 0x1f; + + dt->cs = BCD_TO_BIN(buf[0]); + dt->secs = BCD_TO_BIN(buf[1]); + dt->mins = BCD_TO_BIN(buf[2]); + dt->hours = BCD_TO_BIN(buf[3]); + dt->mday = BCD_TO_BIN(buf[4]); + dt->mon = BCD_TO_BIN(buf[5]); + + ret = 0; + } + + return ret; +} + +static int +pcf8583_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) +{ + unsigned char buf[8]; + int ret, len = 6; + + buf[0] = 0; + buf[1] = DAT(client) | 0x80; + buf[2] = BIN_TO_BCD(dt->cs); + buf[3] = BIN_TO_BCD(dt->secs); + buf[4] = BIN_TO_BCD(dt->mins); + buf[5] = BIN_TO_BCD(dt->hours); + + if (datetoo) { + len = 8; + buf[6] = BIN_TO_BCD(dt->mday) | (dt->year_off << 6); + buf[7] = BIN_TO_BCD(dt->mon) | (dt->wday << 5); + } + + ret = i2c_master_send(client, (char *)buf, len); + + buf[1] = DAT(client); + i2c_master_send(client, (char *)buf, 2); + + return ret; +} + +static int +pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl) +{ + *ctrl = DAT(client); + return 0; +} + +static int +pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl) +{ + unsigned char buf[2]; + + buf[0] = 0; + buf[1] = *ctrl; + DAT(client) = *ctrl; + + return i2c_master_send(client, (char *)buf, 2); +} + +static int +pcf8583_read_mem(struct i2c_client *client, struct mem *mem) +{ + unsigned char addr[1]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 1, addr }, + { client->addr, I2C_M_RD, 0, mem->data } + }; + + if (mem->loc < 8) + return -EINVAL; + + addr[0] = mem->loc; + msgs[1].len = mem->nr; + + return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; +} + +static int +pcf8583_write_mem(struct i2c_client *client, struct mem *mem) +{ + unsigned char addr[1]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 1, addr }, + { client->addr, 0, 0, mem->data } + }; + + if (mem->loc < 8) + return -EINVAL; + + addr[0] = mem->loc; + msgs[1].len = mem->nr; + + return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; +} + +static int +pcf8583_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + switch (cmd) { + case RTC_GETDATETIME: + return pcf8583_get_datetime(client, arg); + + case RTC_SETTIME: + return pcf8583_set_datetime(client, arg, 0); + + case RTC_SETDATETIME: + return pcf8583_set_datetime(client, arg, 1); + + case RTC_GETCTRL: + return pcf8583_get_ctrl(client, arg); + + case RTC_SETCTRL: + return pcf8583_set_ctrl(client, arg); + + case MEM_READ: + return pcf8583_read_mem(client, arg); + + case MEM_WRITE: + return pcf8583_write_mem(client, arg); + + default: + return -EINVAL; + } +} + +static struct i2c_driver pcf8583_driver = { + "PCF8583", + I2C_DRIVERID_PCF8583, + I2C_DF_NOTIFY, + pcf8583_probe, + pcf8583_detach, + pcf8583_command +}; + +static __init int pcf8583_init(void) +{ + return i2c_add_driver(&pcf8583_driver); +} + +__initcall(pcf8583_init); diff -u --recursive --new-file v2.3.42/linux/drivers/acorn/char/pcf8583.h linux/drivers/acorn/char/pcf8583.h --- v2.3.42/linux/drivers/acorn/char/pcf8583.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acorn/char/pcf8583.h Sun Feb 6 17:45:25 2000 @@ -0,0 +1,32 @@ +struct rtc_tm { + unsigned char cs; + unsigned char secs; + unsigned char mins; + unsigned char hours; + unsigned char mday; + unsigned char mon; + unsigned char year_off; + unsigned char wday; +}; + +struct mem { + unsigned int loc; + unsigned int nr; + unsigned char *data; +}; + +#define RTC_GETDATETIME 0 +#define RTC_SETTIME 1 +#define RTC_SETDATETIME 2 +#define RTC_GETCTRL 3 +#define RTC_SETCTRL 4 +#define MEM_READ 5 +#define MEM_WRITE 6 + +#define CTRL_STOP 0x80 +#define CTRL_HOLD 0x40 +#define CTRL_32KHZ 0x00 +#define CTRL_MASK 0x08 +#define CTRL_ALARMEN 0x04 +#define CTRL_ALARM 0x02 +#define CTRL_TIMER 0x01 diff -u --recursive --new-file v2.3.42/linux/drivers/atm/Config.in linux/drivers/atm/Config.in --- v2.3.42/linux/drivers/atm/Config.in Sat Oct 9 11:47:50 1999 +++ linux/drivers/atm/Config.in Tue Feb 8 18:23:13 2000 @@ -8,7 +8,7 @@ fi if [ "$CONFIG_PCI" = "y" ]; then tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI - if [ ! "$CONFIG_ATM_ENI" = "n" ]; then + if [ "$CONFIG_ATM_ENI" != "n" ]; then bool ' Enable extended debugging' CONFIG_ATM_ENI_DEBUG bool ' Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST if [ "$CONFIG_ATM_ENI_TUNE_BURST" = "y" ]; then @@ -23,17 +23,20 @@ fi fi tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM - if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then + if [ "$CONFIG_ATM_ZATM" != "n" ]; then bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG - bool ' Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS + if [ "$CONFIG_X86" = "y" ]; then + bool ' Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS + fi fi # bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y # if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then # bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n # fi - tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR + tristate 'IDT 77201 (NICStAR) (ForeRunnerLE)' CONFIG_ATM_NICSTAR if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then - bool ' Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI + bool ' Use suni PHY driver (155Mbps)' CONFIG_ATM_NICSTAR_USE_SUNI + bool ' Use IDT77015 PHY driver (25Mbps)' CONFIG_ATM_NICSTAR_USE_IDT77105 fi tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then @@ -43,5 +46,9 @@ if [ "$CONFIG_ATM_HORIZON" != "n" ]; then bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG fi + tristate 'Interphase ATM PCI x575/x525/x531' CONFIG_ATM_IA + if [ "$CONFIG_ATM_IA" != "n" ]; then + bool ' Enable debugging messages' CONFIG_ATM_IA_DEBUG + fi fi endmenu diff -u --recursive --new-file v2.3.42/linux/drivers/atm/Makefile linux/drivers/atm/Makefile --- v2.3.42/linux/drivers/atm/Makefile Fri Sep 10 23:57:29 1999 +++ linux/drivers/atm/Makefile Tue Feb 8 18:23:13 2000 @@ -34,21 +34,23 @@ L_OBJS += tneta1570.o suni.o endif -ifeq ($(CONFIG_ATM_FORE200),y) -L_OBJS += fore200.o -endif - ifeq ($(CONFIG_ATM_NICSTAR),y) L_OBJS += nicstar.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) NEED_SUNI_LX = suni.o endif + ifeq ($(CONFIG_ATM_NICSTAR_USE_IDT77105),y) + NEED_IDT77105_LX = idt77105.o + endif else ifeq ($(CONFIG_ATM_NICSTAR),m) M_OBJS += nicstar.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) NEED_SUNI_MX = suni.o endif + ifeq ($(CONFIG_ATM_NICSTAR_USE_IDT77105),y) + NEED_SUNI_MX = idt77105.o + endif endif endif @@ -68,18 +70,34 @@ endif endif +ifeq ($(CONFIG_ATM_TCP),y) +L_OBJS += atmtcp.o +else + ifeq ($(CONFIG_ATM_TCP),m) + M_OBJS += atmtcp.o + endif +endif + +ifeq ($(CONFIG_ATM_IA),y) +L_OBJS += iphase.o +NEED_SUNI_LX = suni.o +else +ifeq ($(CONFIG_ATM_IA),m) + M_OBJS += iphase.o + NEED_SUNI_MX = suni.o + endif +endif + ifeq ($(NEED_SUNI_LX),) MX_OBJS += $(NEED_SUNI_MX) else LX_OBJS += $(NEED_SUNI_LX) endif -ifeq ($(CONFIG_ATM_TCP),y) -L_OBJS += atmtcp.o +ifeq ($(NEED_IDT77105_LX),) + MX_OBJS += $(NEED_IDT77105_MX) else - ifeq ($(CONFIG_ATM_TCP),m) - M_OBJS += atmtcp.o - endif + LX_OBJS += $(NEED_IDT77105_LX) endif EXTRA_CFLAGS=-g diff -u --recursive --new-file v2.3.42/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c --- v2.3.42/linux/drivers/atm/ambassador.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/atm/ambassador.c Tue Feb 8 18:23:13 2000 @@ -1405,7 +1405,7 @@ dont_panic (dev); } else { // moan - return -EINVAL; + return -ENOIOCTLCMD; } } #endif @@ -1654,21 +1654,11 @@ /********** Operation Structure **********/ static const struct atmdev_ops amb_ops = { - NULL, // no amb_dev_close - amb_open, - amb_close, - NULL, // no amb_ioctl, - NULL, // no amb_getsockopt, - NULL, // no amb_setsockopt, - amb_send, - amb_sg_send, - NULL, // no send_oam - not in fact used yet - NULL, // no amb_phy_put - not needed in this driver - NULL, // no amb_phy_get - not needed in this driver - NULL, // no feedback - feedback to the driver! - NULL, // no amb_change_qos - NULL, // amb_free_rx_skb not used until checked by someone else - amb_proc_read + open: amb_open, + close: amb_close, + send: amb_send, + sg_send: amb_sg_send, + proc_read: amb_proc_read }; /********** housekeeping **********/ diff -u --recursive --new-file v2.3.42/linux/drivers/atm/atmdev_init.c linux/drivers/atm/atmdev_init.c --- v2.3.42/linux/drivers/atm/atmdev_init.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/atm/atmdev_init.c Tue Feb 8 18:23:13 2000 @@ -16,9 +16,6 @@ #ifdef CONFIG_ATM_TNETA1570 extern int tneta1570_detect(void); #endif -#ifdef CONFIG_ATM_FORE200 -extern int fore200_detect(void); -#endif #ifdef CONFIG_ATM_NICSTAR extern int nicstar_detect(void); #endif @@ -28,6 +25,9 @@ #ifdef CONFIG_ATM_HORIZON extern int hrz_detect(void); #endif +#ifdef CONFIG_ATM_IA +extern int ia_detect(void); +#endif int __init atmdev_init(void) @@ -44,9 +44,6 @@ #ifdef CONFIG_ATM_TNETA1570 devs += tneta1570_detect(); #endif -#ifdef CONFIG_ATM_FORE200 - devs += fore200_detect(); -#endif #ifdef CONFIG_ATM_NICSTAR devs += nicstar_detect(); #endif @@ -55,6 +52,9 @@ #endif #ifdef CONFIG_ATM_HORIZON devs += hrz_detect(); +#endif +#ifdef CONFIG_ATM_IA + devs += ia_detect(); #endif return devs; } diff -u --recursive --new-file v2.3.42/linux/drivers/atm/atmsar11.data linux/drivers/atm/atmsar11.data --- v2.3.42/linux/drivers/atm/atmsar11.data Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/atmsar11.data Tue Feb 8 18:23:13 2000 @@ -2,12 +2,12 @@ Madge Ambassador ATM Adapter microcode. Copyright (C) 1995-1999 Madge Networks Ltd. - This is provided here for your convenience only. + This microcode data is placed under the terms of the GNU General + Public License. The GPL is contained in /usr/doc/copyright/GPL on a + Debian system and in the file COPYING in the Linux kernel source. - No restrictions are placed on its use, so long as this file remains - unchanged. - - You may not make, use or re-distribute modified versions of this code. + We would prefer you not to distribute modified versions without + consultation and not to ask for assembly/other microcode source. */ 0x401a6800, diff -u --recursive --new-file v2.3.42/linux/drivers/atm/atmsar11.regions linux/drivers/atm/atmsar11.regions --- v2.3.42/linux/drivers/atm/atmsar11.regions Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/atmsar11.regions Tue Feb 8 18:23:13 2000 @@ -1,3 +1,6 @@ +/* + See copyright and licensing conditions in ambassador.* files. +*/ { 0x00000080, 993, }, { 0xa0d0d500, 80, }, { 0xa0d0f000, 978, }, diff -u --recursive --new-file v2.3.42/linux/drivers/atm/atmsar11.start linux/drivers/atm/atmsar11.start --- v2.3.42/linux/drivers/atm/atmsar11.start Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/atmsar11.start Tue Feb 8 18:23:13 2000 @@ -1 +1,4 @@ +/* + See copyright and licensing conditions in ambassador.* files. +*/ 0xa0d0f000 diff -u --recursive --new-file v2.3.42/linux/drivers/atm/atmtcp.c linux/drivers/atm/atmtcp.c --- v2.3.42/linux/drivers/atm/atmtcp.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/atm/atmtcp.c Tue Feb 8 18:23:13 2000 @@ -1,6 +1,6 @@ /* drivers/atm/atmtcp.c - ATM over TCP "device" driver */ -/* Written 1997-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1997-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -8,7 +8,9 @@ #include #include #include -#include "../../net/atm/protocols.h" /* @@@ fix this */ + + +extern int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */ #define PRIV(dev) ((struct atmtcp_dev_data *) ((dev)->dev_data)) @@ -56,7 +58,8 @@ *new_msg = *msg; new_msg->hdr.length = ATMTCP_HDR_MAGIC; new_msg->type = type; - new_msg->vcc = (unsigned long) vcc; + memset(&new_msg->vcc,0,sizeof(atm_kptr_t)); + *(struct atm_vcc **) &new_msg->vcc = vcc; old_flags = vcc->flags; out_vcc->push(out_vcc,skb); while (!((vcc->flags ^ old_flags) & flag)) { @@ -72,7 +75,7 @@ static int atmtcp_recv_control(const struct atmtcp_control *msg) { - struct atm_vcc *vcc = (struct atm_vcc *) msg->vcc; + struct atm_vcc *vcc = *(struct atm_vcc **) &msg->vcc; vcc->vpi = msg->addr.sap_addr.vpi; vcc->vci = msg->addr.sap_addr.vci; @@ -143,7 +146,7 @@ struct atm_cirange ci; struct atm_vcc *vcc; - if (cmd != ATM_SETCIRANGE) return -EINVAL; + if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD; if (copy_from_user(&ci,(void *) arg,sizeof(ci))) return -EFAULT; if (ci.vpi_bits == ATM_CI_MAX) ci.vpi_bits = MAX_VPI_BITS; if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS; @@ -190,6 +193,8 @@ if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); out_vcc->push(out_vcc,new_skb); + vcc->stats->tx++; + out_vcc->stats->rx++; return 0; } @@ -258,6 +263,8 @@ new_skb->stamp = xtime; memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); out_vcc->push(out_vcc,new_skb); + vcc->stats->tx++; + out_vcc->stats->rx++; done: if (vcc->pop) vcc->pop(vcc,skb); else dev_kfree_skb(skb); @@ -271,21 +278,12 @@ static struct atmdev_ops atmtcp_v_dev_ops = { - atmtcp_v_dev_close, - atmtcp_v_open, - atmtcp_v_close, - atmtcp_v_ioctl, - NULL, /* no getsockopt */ - NULL, /* no setsockopt */ - atmtcp_v_send, - NULL, /* no direct writes */ - NULL, /* no send_oam */ - NULL, /* no phy_put */ - NULL, /* no phy_get */ - NULL, /* no feedback */ - NULL, /* no change_qos */ - NULL, /* no free_rx_skb */ - atmtcp_v_proc /* proc_read */ + dev_close: atmtcp_v_dev_close, + open: atmtcp_v_open, + close: atmtcp_v_close, + ioctl: atmtcp_v_ioctl, + send: atmtcp_v_send, + proc_read: atmtcp_v_proc }; @@ -295,21 +293,8 @@ static struct atmdev_ops atmtcp_c_dev_ops = { - NULL, /* no dev_close */ - NULL, /* no open */ - atmtcp_c_close, - NULL, /* no ioctl */ - NULL, /* no getsockopt */ - NULL, /* no setsockopt */ - atmtcp_c_send, - NULL, /* no sg_send */ - NULL, /* no send_oam */ - NULL, /* no phy_put */ - NULL, /* no phy_get */ - NULL, /* no feedback */ - NULL, /* no change_qos */ - NULL, /* no free_rx_skb */ - NULL /* no proc_read */ + close: atmtcp_c_close, + send: atmtcp_c_send }; diff -u --recursive --new-file v2.3.42/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.3.42/linux/drivers/atm/eni.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/atm/eni.c Tue Feb 8 18:23:13 2000 @@ -1,6 +1,6 @@ /* drivers/atm/eni.c - Efficient Networks ENI155P device driver */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -774,7 +774,7 @@ eni_vcc = ENI_VCC(vcc); eni_vcc->rx = NULL; if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; - size = vcc->qos.rxtp.max_sdu*3; /* @@@ improve this */ + size = vcc->qos.rxtp.max_sdu*eni_dev->rx_mult/100; if (size > MID_MAX_BUF_SIZE && vcc->qos.rxtp.max_sdu <= MID_MAX_BUF_SIZE) size = MID_MAX_BUF_SIZE; @@ -885,6 +885,7 @@ return -ENOMEM; } memset(eni_dev->rx_map,0,PAGE_SIZE); + eni_dev->rx_mult = DEFAULT_RX_MULT; eni_dev->fast = eni_dev->last_fast = NULL; eni_dev->slow = eni_dev->last_slow = NULL; init_waitqueue_head(&eni_dev->rx_wait); @@ -1151,7 +1152,8 @@ if (tx->send) while ((skb = skb_dequeue(&tx->backlog))) { res = do_tx(skb); - if (res != enq_ok) { + if (res == enq_ok) tx->backlog_len--; + else { DPRINTK("re-queuing TX PDU\n"); skb_queue_head(&tx->backlog,skb); requeued++; @@ -1258,7 +1260,7 @@ unlimited = ubr && (!rate || rate <= -ATM_OC3_PCR || rate >= ATM_OC3_PCR); if (!unlimited) { - size = txtp->max_sdu*3; /* @@@ improve */ + size = txtp->max_sdu*eni_dev->tx_mult/100; if (size > MID_MAX_BUF_SIZE && txtp->max_sdu <= MID_MAX_BUF_SIZE) size = MID_MAX_BUF_SIZE; @@ -1287,6 +1289,7 @@ tx->send = mem; tx->words = size >> 2; skb_queue_head_init(&tx->backlog); + tx->backlog_len = 0; for (order = 0; size > (1 << (order+10)); order++); eni_out((order << MID_SIZE_SHIFT) | ((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)), @@ -1390,6 +1393,7 @@ eni_dev = ENI_DEV(dev); eni_dev->lost = 0; eni_dev->tx_bw = ATM_OC3_PCR; + eni_dev->tx_mult = DEFAULT_TX_MULT; init_waitqueue_head(&eni_dev->tx_wait); eni_dev->ubr = NULL; skb_queue_head_init(&eni_dev->tx_queue); @@ -1643,7 +1647,7 @@ struct midway_eprom *eprom; struct eni_dev *eni_dev; struct pci_dev *pci_dev; - unsigned int real_base,base; + unsigned long real_base,base; unsigned char revision; int error,i,last; @@ -1668,7 +1672,7 @@ "(0x%02x)\n",dev->number,error); return error; } - printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", + printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,", dev->number,revision,real_base,eni_dev->irq); if (!(base = (unsigned long) ioremap_nocache(real_base,MAP_MAX_SIZE))) { printk("\n"); @@ -1748,6 +1752,10 @@ "master (0x%02x)\n",dev->number,error); return error; } +#ifdef __sparc_v9__ /* copied from drivers/net/sunhme.c */ + /* NOTE: Cache line size is in 32-bit word units. */ + pci_write_config_byte(eni_dev->pci_dev, PCI_CACHE_LINE_SIZE, 0x10); +#endif if ((error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL, END_SWAP_DMA))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't set endian swap " @@ -1947,12 +1955,29 @@ static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) { + struct eni_dev *eni_dev = ENI_DEV(dev); + if (cmd == ENI_MEMDUMP) { + if (!capable(CAP_NET_ADMIN)) return -EPERM; printk(KERN_WARNING "Please use /proc/atm/" DEV_LABEL ":%d " "instead of obsolete ioctl ENI_MEMDUMP\n",dev->number); dump(dev); return 0; } + if (cmd == ENI_SETMULT) { + struct eni_multipliers mult; + + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (copy_from_user(&mult,(void *) arg, + sizeof(struct eni_multipliers))) + return -EFAULT; + if ((mult.tx && mult.tx <= 100) || (mult.rx &&mult.rx <= 100) || + mult.tx > 65536 || mult.rx > 65536) + return -EINVAL; + if (mult.tx) eni_dev->tx_mult = mult.tx; + if (mult.rx) eni_dev->rx_mult = mult.rx; + return 0; + } if (cmd == ATM_SETCIRANGE) { struct atm_cirange ci; @@ -1963,7 +1988,7 @@ return 0; return -EINVAL; } - if (!dev->phy->ioctl) return -EINVAL; + if (!dev->phy->ioctl) return -ENOIOCTLCMD; return dev->phy->ioctl(dev,cmd,arg); } @@ -1971,21 +1996,6 @@ static int eni_getsockopt(struct atm_vcc *vcc,int level,int optname, void *optval,int optlen) { -#ifdef CONFIG_MMU_HACKS - -static const struct atm_buffconst bctx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; -static const struct atm_buffconst bcrx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; - -#else - -static const struct atm_buffconst bctx = { sizeof(int),0,sizeof(int),0,0,0 }; -static const struct atm_buffconst bcrx = { sizeof(int),0,sizeof(int),0,0,0 }; - -#endif - if (level == SOL_AAL && (optname == SO_BCTXOPT || - optname == SO_BCRXOPT)) - return copy_to_user(optval,optname == SO_BCTXOPT ? &bctx : - &bcrx,sizeof(struct atm_buffconst)) ? -EFAULT : 0; return -EINVAL; } @@ -2027,7 +2037,8 @@ cli(); /* brute force */ if (skb_peek(&ENI_VCC(vcc)->tx->backlog) || do_tx(skb)) { skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb); - backlogged++; + ENI_VCC(vcc)->tx->backlog_len++; +backlogged++; } restore_flags(flags); return 0; @@ -2068,9 +2079,8 @@ return sprintf(page,DEV_LABEL "(itf %d) signal %s, %dkB, " "%d cps remaining\n",dev->number,signal[(int) dev->signal], eni_dev->mem >> 10,eni_dev->tx_bw); - left--; - if (!left) - return sprintf(page,"Bursts: TX" + if (!--left) + return sprintf(page,"%4sBursts: TX" #if !defined(CONFIG_ATM_ENI_BURST_TX_16W) && \ !defined(CONFIG_ATM_ENI_BURST_TX_8W) && \ !defined(CONFIG_ATM_ENI_BURST_TX_4W) && \ @@ -2111,18 +2121,25 @@ #ifndef CONFIG_ATM_ENI_TUNE_BURST " (default)" #endif - "\n"); + "\n",""); + if (!--left) + return sprintf(page,"%4sBuffer multipliers: tx %d%%, rx %d%%\n", + "",eni_dev->tx_mult,eni_dev->rx_mult); for (i = 0; i < NR_CHAN; i++) { struct eni_tx *tx = eni_dev->tx+i; if (!tx->send) continue; + if (!--left) { + return sprintf(page,"tx[%d]: 0x%06lx-0x%06lx " + "(%6ld bytes), rsv %d cps, shp %d cps%s\n",i, + tx->send-eni_dev->ram, + tx->send-eni_dev->ram+tx->words*4-1,tx->words*4, + tx->reserved,tx->shaping, + tx == eni_dev->ubr ? " (UBR)" : ""); + } if (--left) continue; - return sprintf(page,"tx[%d]: 0x%06lx-0x%06lx (%6ld bytes), " - "rsv %d cps, shp %d cps%s\n",i, - tx->send-eni_dev->ram, - tx->send-eni_dev->ram+tx->words*4-1,tx->words*4, - tx->reserved,tx->shaping, - tx == eni_dev->ubr ? " (UBR)" : ""); + return sprintf(page,"%10sbacklog %d bytes\n","", + tx->backlog_len); } for (vcc = dev->vccs; vcc; vcc = vcc->next) { struct eni_vcc *eni_vcc = ENI_VCC(vcc); @@ -2139,8 +2156,8 @@ if (eni_vcc->tx) length += sprintf(page+length,", "); } if (eni_vcc->tx) - length += sprintf(page+length,"tx[%d]", - eni_vcc->tx->index); + length += sprintf(page+length,"tx[%d], txing %d bytes", + eni_vcc->tx->index,eni_vcc->txing); page[length] = '\n'; return length+1; } @@ -2159,21 +2176,17 @@ static const struct atmdev_ops ops = { - NULL, /* no dev_close */ - eni_open, - eni_close, - eni_ioctl, - eni_getsockopt, - eni_setsockopt, - eni_send, - eni_sg_send, - NULL, /* no send_oam */ - eni_phy_put, - eni_phy_get, - NULL, /* no feedback */ - eni_change_qos, /* no change_qos */ - NULL, /* no free_rx_skb */ - eni_proc_read + open: eni_open, + close: eni_close, + ioctl: eni_ioctl, + getsockopt: eni_getsockopt, + setsockopt: eni_setsockopt, + send: eni_send, + sg_send: eni_sg_send, + phy_put: eni_phy_put, + phy_get: eni_phy_get, + change_qos: eni_change_qos, + proc_read: eni_proc_read }; diff -u --recursive --new-file v2.3.42/linux/drivers/atm/eni.h linux/drivers/atm/eni.h --- v2.3.42/linux/drivers/atm/eni.h Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/eni.h Tue Feb 8 18:23:13 2000 @@ -1,6 +1,6 @@ /* drivers/atm/eni.h - Efficient Networks ENI155P device driver declarations */ -/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #ifndef DRIVER_ATM_ENI_H @@ -24,6 +24,9 @@ #define RX_DMA_BUF 8 /* burst and skip a few things */ #define TX_DMA_BUF 100 /* should be enough for 64 kB */ +#define DEFAULT_RX_MULT 300 /* max_sdu*3 */ +#define DEFAULT_TX_MULT 300 /* max_sdu*3 */ + struct eni_free { unsigned long start; /* counting in bytes */ @@ -40,6 +43,7 @@ int reserved; /* reserved peak cell rate */ int shaping; /* shaped peak cell rate */ struct sk_buff_head backlog; /* queue of waiting TX buffers */ + int backlog_len; /* length of backlog in bytes */ }; struct eni_vcc { @@ -51,7 +55,7 @@ struct eni_tx *tx; /* TXer, NULL if none */ int rxing; /* number of pending PDUs */ int servicing; /* number of waiting VCs (0 or 1) */ - int txing; /* number of pending TX cells/PDUs */ + int txing; /* number of pending TX bytes */ struct timeval timestamp; /* for RX timing */ struct atm_vcc *next; /* next pending RX */ struct sk_buff *last; /* last PDU being DMAed (used to carry @@ -75,6 +79,7 @@ wait_queue_head_t tx_wait; /* for close */ int tx_bw; /* remaining bandwidth */ u32 dma[TX_DMA_BUF*2]; /* DMA request scratch area */ + int tx_mult; /* buffer size multiplier (percent) */ /*-------------------------------- RX part */ u32 serv_read; /* host service read index */ struct atm_vcc *fast,*last_fast;/* queues of VCCs with pending PDUs */ @@ -82,6 +87,7 @@ struct atm_vcc **rx_map; /* for fast lookups */ struct sk_buff_head rx_queue; /* PDUs currently being RX-DMAed */ wait_queue_head_t rx_wait; /* for close */ + int rx_mult; /* buffer size multiplier (percent) */ /*-------------------------------- statistics */ unsigned long lost; /* number of lost cells (RX) */ /*-------------------------------- memory management */ @@ -94,7 +100,7 @@ /*-------------------------------- general information */ int mem; /* RAM on board (in bytes) */ int asic; /* PCI interface type, 0 for FPGA */ - unsigned char irq; /* IRQ */ + unsigned int irq; /* IRQ */ struct pci_dev *pci_dev; /* PCI stuff */ }; diff -u --recursive --new-file v2.3.42/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c --- v2.3.42/linux/drivers/atm/horizon.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/atm/horizon.c Tue Feb 8 18:23:13 2000 @@ -2623,12 +2623,10 @@ switch (level) { case SOL_SOCKET: switch (optname) { - case SO_BCTXOPT: - // return the right thing - break; - case SO_BCRXOPT: - // return the right thing - break; +// case SO_BCTXOPT: +// break; +// case SO_BCRXOPT: +// break; default: return -ENOPROTOOPT; break; @@ -2645,12 +2643,10 @@ switch (level) { case SOL_SOCKET: switch (optname) { - case SO_BCTXOPT: - // not settable - break; - case SO_BCRXOPT: - // not settable - break; +// case SO_BCTXOPT: +// break; +// case SO_BCRXOPT: +// break; default: return -ENOPROTOOPT; break; @@ -2743,21 +2739,11 @@ } static const struct atmdev_ops hrz_ops = { - NULL, // no hrz_dev_close - hrz_open, - hrz_close, - NULL, // no hrz_ioctl - NULL, // hrz_getsockopt, - NULL, // hrz_setsockopt, - hrz_send, - hrz_sg_send, - NULL, // no send_oam - not in fact used yet - NULL, // no hrz_phy_put - not needed in this driver - NULL, // no hrz_phy_get - not needed in this driver - NULL, // no feedback - feedback to the driver! - NULL, // no hrz_change_qos - NULL, // no free_rx_skb - hrz_proc_read + open: hrz_open, + close: hrz_close, + send: hrz_send, + sg_send: hrz_sg_send, + proc_read: hrz_proc_read }; static int __init hrz_probe (void) { diff -u --recursive --new-file v2.3.42/linux/drivers/atm/idt77105.c linux/drivers/atm/idt77105.c --- v2.3.42/linux/drivers/atm/idt77105.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/idt77105.c Tue Feb 8 18:23:13 2000 @@ -0,0 +1,385 @@ +/* drivers/atm/idt77105.c - IDT77105 (PHY) driver */ + +/* Written 1999 by Greg Banks, NEC Australia . Based on suni.c */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "idt77105.h" + +#undef GENERAL_DEBUG + +#ifdef GENERAL_DEBUG +#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) +#else +#define DPRINTK(format,args...) +#endif + + +struct idt77105_priv { + struct idt77105_stats stats; /* link diagnostics */ + struct atm_dev *dev; /* device back-pointer */ + struct idt77105_priv *next; + int loop_mode; + unsigned char old_mcr; /* storage of MCR reg while signal lost */ +}; + + +#define PRIV(dev) ((struct idt77105_priv *) dev->phy_data) + +#define PUT(val,reg) dev->ops->phy_put(dev,val,IDT77105_##reg) +#define GET(reg) dev->ops->phy_get(dev,IDT77105_##reg) + +static void idt77105_stats_timer_func(unsigned long); +static void idt77105_restart_timer_func(unsigned long); + + +static struct timer_list stats_timer = { NULL, NULL, 0L, 0L, + &idt77105_stats_timer_func }; +static struct timer_list restart_timer = { NULL, NULL, 0L, 0L, + &idt77105_restart_timer_func }; +static int start_timer = 1; +static struct idt77105_priv *idt77105_all = NULL; + +/* + * Retrieve the value of one of the IDT77105's counters. + * `counter' is one of the IDT77105_CTRSEL_* constants. + */ +static u16 get_counter(struct atm_dev *dev, int counter) +{ + u16 val; + + /* write the counter bit into PHY register 6 */ + PUT(counter, CTRSEL); + /* read the low 8 bits from register 4 */ + val = GET(CTRLO); + /* read the high 8 bits from register 5 */ + val |= GET(CTRHI)<<8; + + return val; +} + +/* + * Timer function called every second to gather statistics + * from the 77105. This is done because the h/w registers + * will overflow if not read at least once per second. The + * kernel's stats are much higher precision. Also, having + * a separate copy of the stats allows implementation of + * an ioctl which gathers the stats *without* zero'ing them. + */ +static void idt77105_stats_timer_func(unsigned long dummy) +{ + struct idt77105_priv *walk; + struct atm_dev *dev; + struct idt77105_stats *stats; + + DPRINTK("IDT77105 gathering statistics\n"); + for (walk = idt77105_all; walk; walk = walk->next) { + dev = walk->dev; + + stats = &walk->stats; + stats->symbol_errors += get_counter(dev, IDT77105_CTRSEL_SEC); + stats->tx_cells += get_counter(dev, IDT77105_CTRSEL_TCC); + stats->rx_cells += get_counter(dev, IDT77105_CTRSEL_RCC); + stats->rx_hec_errors += get_counter(dev, IDT77105_CTRSEL_RHEC); + } + if (!start_timer) mod_timer(&stats_timer,jiffies+IDT77105_STATS_TIMER_PERIOD); +} + + +/* + * A separate timer func which handles restarting PHY chips which + * have had the cable re-inserted after being pulled out. This is + * done by polling the Good Signal Bit in the Interrupt Status + * register every 5 seconds. The other technique (checking Good + * Signal Bit in the interrupt handler) cannot be used because PHY + * interrupts need to be disabled when the cable is pulled out + * to avoid lots of spurious cell error interrupts. + */ +static void idt77105_restart_timer_func(unsigned long dummy) +{ + struct idt77105_priv *walk; + struct atm_dev *dev; + unsigned char istat; + + DPRINTK("IDT77105 checking for cable re-insertion\n"); + for (walk = idt77105_all; walk; walk = walk->next) { + dev = walk->dev; + + if (dev->signal != ATM_PHY_SIG_LOST) + continue; + + istat = GET(ISTAT); /* side effect: clears all interrupt status bits */ + if (istat & IDT77105_ISTAT_GOODSIG) { + /* Found signal again */ + dev->signal = ATM_PHY_SIG_FOUND; + printk(KERN_NOTICE "%s(itf %d): signal detected again\n", + dev->type,dev->number); + /* flush the receive FIFO */ + PUT( GET(DIAG) | IDT77105_DIAG_RFLUSH, DIAG); + /* re-enable interrupts */ + PUT( walk->old_mcr ,MCR); + } + } + if (!start_timer) mod_timer(&restart_timer,jiffies+IDT77105_RESTART_TIMER_PERIOD); +} + + +static int fetch_stats(struct atm_dev *dev,struct idt77105_stats *arg,int zero) +{ + unsigned long flags; + int error; + + error = 0; + save_flags(flags); + cli(); + if (arg) + error = copy_to_user(arg,&PRIV(dev)->stats, + sizeof(struct idt77105_stats)); + if (zero && !error) + memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats)); + restore_flags(flags); + return error ? -EFAULT : sizeof(struct idt77105_stats); +} + + + +static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg) +{ + printk(KERN_NOTICE "%s(%d) idt77105_ioctl() called\n",dev->type,dev->number); + switch (cmd) { + case IDT77105_GETSTATZ: + case IDT77105_GETSTAT: + return fetch_stats(dev,(struct idt77105_stats *) arg, + cmd == IDT77105_GETSTATZ); + case IDT77105_SETLOOP: + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if ((int) arg < 0 || (int) arg > IDT77105_LM_LOOP) + return -EINVAL; + PUT((GET(DIAG) & ~IDT77105_DIAG_LCMASK) | + ((int) arg == IDT77105_LM_NONE ? IDT77105_DIAG_LC_NORMAL : 0) | + ((int) arg == IDT77105_LM_DIAG ? IDT77105_DIAG_LC_PHY_LOOPBACK : 0) | + ((int) arg == IDT77105_LM_LOOP ? IDT77105_DIAG_LC_LINE_LOOPBACK : 0), + DIAG); + printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n", + dev->type, dev->number, + ((int) arg == IDT77105_LM_NONE ? "NONE" : + ((int) arg == IDT77105_LM_DIAG ? "DIAG (local)" : + ((int) arg == IDT77105_LM_LOOP ? "LOOP (remote)" : + "unknown"))) + ); + PRIV(dev)->loop_mode = (int) arg; + return 0; + case IDT77105_GETLOOP: + return put_user(PRIV(dev)->loop_mode,(int *) arg) ? + -EFAULT : sizeof(int); + default: + return -ENOIOCTLCMD; + } +} + + + +static void idt77105_int(struct atm_dev *dev) +{ + unsigned char istat; + + istat = GET(ISTAT); /* side effect: clears all interrupt status bits */ + + DPRINTK("IDT77105 generated an interrupt, istat=%02x\n", (unsigned)istat); + + if (istat & IDT77105_ISTAT_RSCC) { + /* Rx Signal Condition Change - line went up or down */ + if (istat & IDT77105_ISTAT_GOODSIG) { /* signal detected again */ + /* This should not happen (restart timer does it) but JIC */ + dev->signal = ATM_PHY_SIG_FOUND; + } else { /* signal lost */ + /* + * Disable interrupts and stop all transmission and + * reception - the restart timer will restore these. + */ + PRIV(dev)->old_mcr = GET(MCR); + PUT( + (PRIV(dev)->old_mcr| + IDT77105_MCR_DREC| + IDT77105_MCR_DRIC| + IDT77105_MCR_HALTTX + ) & ~IDT77105_MCR_EIP, MCR); + dev->signal = ATM_PHY_SIG_LOST; + printk(KERN_NOTICE "%s(itf %d): signal lost\n", + dev->type,dev->number); + } + } + + if (istat & IDT77105_ISTAT_RFO) { + /* Rx FIFO Overrun -- perform a FIFO flush */ + PUT( GET(DIAG) | IDT77105_DIAG_RFLUSH, DIAG); + printk(KERN_NOTICE "%s(itf %d): receive FIFO overrun\n", + dev->type,dev->number); + } +#ifdef GENERAL_DEBUG + if (istat & (IDT77105_ISTAT_HECERR | IDT77105_ISTAT_SCR | + IDT77105_ISTAT_RSE)) { + /* normally don't care - just report in stats */ + printk(KERN_NOTICE "%s(itf %d): received cell with error\n", + dev->type,dev->number); + } +#endif +} + + +static int idt77105_start(struct atm_dev *dev) +{ + unsigned long flags; + + if (!(PRIV(dev) = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL))) + return -ENOMEM; + PRIV(dev)->dev = dev; + save_flags(flags); + cli(); + PRIV(dev)->next = idt77105_all; + idt77105_all = PRIV(dev); + restore_flags(flags); + memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats)); + + /* initialise dev->signal from Good Signal Bit */ + dev->signal = GET(ISTAT) & IDT77105_ISTAT_GOODSIG ? ATM_PHY_SIG_FOUND : + ATM_PHY_SIG_LOST; + if (dev->signal == ATM_PHY_SIG_LOST) + printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type, + dev->number); + + /* initialise loop mode from hardware */ + switch ( GET(DIAG) & IDT77105_DIAG_LCMASK ) { + case IDT77105_DIAG_LC_NORMAL: + PRIV(dev)->loop_mode = IDT77105_LM_NONE; + break; + case IDT77105_DIAG_LC_PHY_LOOPBACK: + PRIV(dev)->loop_mode = IDT77105_LM_DIAG; + break; + case IDT77105_DIAG_LC_LINE_LOOPBACK: + PRIV(dev)->loop_mode = IDT77105_LM_LOOP; + break; + } + + /* enable interrupts, e.g. on loss of signal */ + PRIV(dev)->old_mcr = GET(MCR); + if (dev->signal == ATM_PHY_SIG_FOUND) { + PRIV(dev)->old_mcr |= IDT77105_MCR_EIP; + PUT(PRIV(dev)->old_mcr, MCR); + } + + + idt77105_stats_timer_func(0); /* clear 77105 counters */ + (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ + + cli(); + if (!start_timer) restore_flags(flags); + else { + start_timer = 0; + restore_flags(flags); + + init_timer(&stats_timer); + stats_timer.expires = jiffies+IDT77105_STATS_TIMER_PERIOD; + stats_timer.function = idt77105_stats_timer_func; + add_timer(&stats_timer); + + init_timer(&restart_timer); + restart_timer.expires = jiffies+IDT77105_RESTART_TIMER_PERIOD; + restart_timer.function = idt77105_restart_timer_func; + add_timer(&restart_timer); + } + return 0; +} + + +static const struct atmphy_ops idt77105_ops = { + idt77105_start, + idt77105_ioctl, + idt77105_int +}; + + +int __init idt77105_init(struct atm_dev *dev) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif /* MODULE */ + + dev->phy = &idt77105_ops; + return 0; +} + + +/* + * TODO: this function should be called through phy_ops + * but that will not be possible for some time as there is + * currently a freeze on modifying that structure + * -- Greg Banks, 13 Sep 1999 + */ +int idt77105_stop(struct atm_dev *dev) +{ + struct idt77105_priv *walk, *prev; + + DPRINTK("%s(itf %d): stopping IDT77105\n",dev->type,dev->number); + + /* disable interrupts */ + PUT( GET(MCR) & ~IDT77105_MCR_EIP, MCR ); + + /* detach private struct from atm_dev & free */ + for (prev = NULL, walk = idt77105_all ; + walk != NULL; + prev = walk, walk = walk->next) { + if (walk->dev == dev) { + if (prev != NULL) + prev->next = walk->next; + else + idt77105_all = walk->next; + dev->phy = NULL; + PRIV(dev) = NULL; + kfree(walk); + break; + } + } + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif /* MODULE */ + return 0; +} + + + +EXPORT_SYMBOL(idt77105_init); +EXPORT_SYMBOL(idt77105_stop); + +#ifdef MODULE + +int init_module(void) +{ + return 0; +} + + +void cleanup_module(void) +{ + /* turn off timers */ + del_timer(&stats_timer); + del_timer(&restart_timer); +} + +#endif diff -u --recursive --new-file v2.3.42/linux/drivers/atm/idt77105.h linux/drivers/atm/idt77105.h --- v2.3.42/linux/drivers/atm/idt77105.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/idt77105.h Tue Feb 8 18:23:13 2000 @@ -0,0 +1,92 @@ +/* drivers/atm/idt77105.h - IDT77105 (PHY) declarations */ + +/* Written 1999 by Greg Banks, NEC Australia . Based on suni.h */ + + +#ifndef DRIVER_ATM_IDT77105_H +#define DRIVER_ATM_IDT77105_H + +#include +#include + + +/* IDT77105 registers */ + +#define IDT77105_MCR 0x0 /* Master Control Register */ +#define IDT77105_ISTAT 0x1 /* Interrupt Status */ +#define IDT77105_DIAG 0x2 /* Diagnostic Control */ +#define IDT77105_LEDHEC 0x3 /* LED Driver & HEC Status/Control */ +#define IDT77105_CTRLO 0x4 /* Low Byte Counter Register */ +#define IDT77105_CTRHI 0x5 /* High Byte Counter Register */ +#define IDT77105_CTRSEL 0x6 /* Counter Register Read Select */ + +/* IDT77105 register values */ + +/* MCR */ +#define IDT77105_MCR_UPLO 0x80 /* R/W, User Prog'le Output Latch */ +#define IDT77105_MCR_DREC 0x40 /* R/W, Discard Receive Error Cells */ +#define IDT77105_MCR_ECEIO 0x20 /* R/W, Enable Cell Error Interrupts + * Only */ +#define IDT77105_MCR_TDPC 0x10 /* R/W, Transmit Data Parity Check */ +#define IDT77105_MCR_DRIC 0x08 /* R/W, Discard Received Idle Cells */ +#define IDT77105_MCR_HALTTX 0x04 /* R/W, Halt Tx */ +#define IDT77105_MCR_UMODE 0x02 /* R/W, Utopia (cell/byte) Mode */ +#define IDT77105_MCR_EIP 0x01 /* R/W, Enable Interrupt Pin */ + +/* ISTAT */ +#define IDT77105_ISTAT_GOODSIG 0x40 /* R, Good Signal Bit */ +#define IDT77105_ISTAT_HECERR 0x20 /* sticky, HEC Error*/ +#define IDT77105_ISTAT_SCR 0x10 /* sticky, Short Cell Received */ +#define IDT77105_ISTAT_TPE 0x08 /* sticky, Transmit Parity Error */ +#define IDT77105_ISTAT_RSCC 0x04 /* sticky, Rx Signal Condition Change */ +#define IDT77105_ISTAT_RSE 0x02 /* sticky, Rx Symbol Error */ +#define IDT77105_ISTAT_RFO 0x01 /* sticky, Rx FIFO Overrun */ + +/* DIAG */ +#define IDT77105_DIAG_FTD 0x80 /* R/W, Force TxClav deassert */ +#define IDT77105_DIAG_ROS 0x40 /* R/W, RxClav operation select */ +#define IDT77105_DIAG_MPCS 0x20 /* R/W, Multi-PHY config'n select */ +#define IDT77105_DIAG_RFLUSH 0x10 /* R/W, clear receive FIFO */ +#define IDT77105_DIAG_ITPE 0x08 /* R/W, Insert Tx payload error */ +#define IDT77105_DIAG_ITHE 0x04 /* R/W, Insert Tx HEC error */ +#define IDT77105_DIAG_UMODE 0x02 /* R/W, Utopia (cell/byte) Mode */ +#define IDT77105_DIAG_LCMASK 0x03 /* R/W, Loopback Control */ + +#define IDT77105_DIAG_LC_NORMAL 0x00 /* Receive from network */ +#define IDT77105_DIAG_LC_PHY_LOOPBACK 0x02 +#define IDT77105_DIAG_LC_LINE_LOOPBACK 0x03 + +/* LEDHEC */ +#define IDT77105_LEDHEC_DRHC 0x40 /* R/W, Disable Rx HEC check */ +#define IDT77105_LEDHEC_DTHC 0x20 /* R/W, Disable Tx HEC calculation */ +#define IDT77105_LEDHEC_RPWMASK 0x18 /* R/W, RxRef pulse width select */ +#define IDT77105_LEDHEC_TFS 0x04 /* R, Tx FIFO Status (1=empty) */ +#define IDT77105_LEDHEC_TLS 0x02 /* R, Tx LED Status (1=lit) */ +#define IDT77105_LEDHEC_RLS 0x01 /* R, Rx LED Status (1=lit) */ + +#define IDT77105_LEDHEC_RPW_1 0x00 /* RxRef active for 1 RxClk cycle */ +#define IDT77105_LEDHEC_RPW_2 0x08 /* RxRef active for 2 RxClk cycle */ +#define IDT77105_LEDHEC_RPW_4 0x10 /* RxRef active for 4 RxClk cycle */ +#define IDT77105_LEDHEC_RPW_8 0x18 /* RxRef active for 8 RxClk cycle */ + +/* CTRSEL */ +#define IDT77105_CTRSEL_SEC 0x08 /* W, Symbol Error Counter */ +#define IDT77105_CTRSEL_TCC 0x04 /* W, Tx Cell Counter */ +#define IDT77105_CTRSEL_RCC 0x02 /* W, Rx Cell Counter */ +#define IDT77105_CTRSEL_RHEC 0x01 /* W, Rx HEC Error Counter */ + +#ifdef __KERNEL__ +int idt77105_init(struct atm_dev *dev) __init; +int idt77105_stop(struct atm_dev *dev); +#endif + +/* + * Tunable parameters + */ + +/* Time between samples of the hardware cell counters. Should be <= 1 sec */ +#define IDT77105_STATS_TIMER_PERIOD (HZ) +/* Time between checks to see if the signal has been found again */ +#define IDT77105_RESTART_TIMER_PERIOD (5 * HZ) + +#endif diff -u --recursive --new-file v2.3.42/linux/drivers/atm/iphase.c linux/drivers/atm/iphase.c --- v2.3.42/linux/drivers/atm/iphase.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/iphase.c Tue Feb 8 22:27:11 2000 @@ -0,0 +1,3313 @@ +/****************************************************************************** + iphase.c: Device driver for Interphase ATM PCI adapter cards + Author: Peter Wang + Interphase Corporation + Version: 1.0 +******************************************************************************* + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + Drivers based on this skeleton fall under the GPL and must retain + the authorship (implicit copyright) notice. + + 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. + + Modified from an incomplete driver for Interphase 5575 1KVC 1M card which + was originally written by Monalisa Agrawal at UNH. Now this driver + supports a variety of varients of Interphase ATM PCI (i)Chip adapter + card family (See www.iphase.com/products/ClassSheet.cfm?ClassID=ATM) + in terms of PHY type, the size of control memory and the size of + packet memory. The followings are the change log and history: + + Bugfix the Mona's UBR driver. + Modify the basic memory allocation and dma logic. + Port the driver to the latest kernel from 2.0.46. + Complete the ABR logic of the driver, and added the ABR work- + around for the hardware anormalies. + Add the CBR support. + Add the flow control logic to the driver to allow rate-limit VC. + Add 4K VC support to the board with 512K control memory. + Add the support of all the variants of the Interphase ATM PCI + (i)Chip adapter cards including x575 (155M OC3 and UTP155), x525 + (25M UTP25) and x531 (DS3 and E3). + Add SMP support. + + Support and updates available at: ftp://ftp.iphase.com/pub/atm + +*******************************************************************************/ + +#ifdef IA_MODULE +#define MODULE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for xtime */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iphase.h" +#include "suni.h" +#define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) +struct suni_priv { + struct sonet_stats sonet_stats; /* link diagnostics */ + unsigned char loop_mode; /* loopback mode */ + struct atm_dev *dev; /* device back-pointer */ + struct suni_priv *next; /* next SUNI */ +}; +#define PRIV(dev) ((struct suni_priv *) dev->phy_data) + +static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr); + +static IADEV *ia_dev[8] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +static struct atm_dev *_ia_dev[8] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +static int iadev_count = 0; +static struct timer_list ia_timer; +struct atm_vcc *vcc_close_que[100]; +static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ; +static int IA_RX_BUF = DFL_RX_BUFFERS, IA_RX_BUF_SZ = DFL_RX_BUF_SZ; +static u32 IADebugFlag = /* IF_IADBG_ERR | IF_IADBG_CBR| IF_IADBG_INIT_ADAPTER + |IF_IADBG_ABR | IF_IADBG_EVENT*/ 0; + +#ifdef MODULE +MODULE_PARM(IA_TX_BUF, "i"); +MODULE_PARM(IA_TX_BUF_SZ, "i"); +MODULE_PARM(IA_RX_BUF, "i"); +MODULE_PARM(IA_RX_BUF_SZ, "i"); +MODULE_PARM(IADebugFlag, "i"); +#endif + +/**************************** IA_LIB **********************************/ + +static void ia_init_rtn_q (IARTN_Q *que) +{ + que->next = NULL; + que->tail = NULL; +} + +static void ia_enque_head_rtn_q (IARTN_Q *que, IARTN_Q * data) +{ + data->next = NULL; + if (que->next == NULL) + que->next = que->tail = data; + else { + data->next = que->next; + que->next = data; + } + return; +} + +static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) { + IARTN_Q *entry; + entry = (IARTN_Q *)kmalloc(sizeof(IARTN_Q), GFP_KERNEL); + if (!entry) return -1; + entry->data = data; + entry->next = NULL; + if (que->next == NULL) + que->next = que->tail = entry; + else { + que->tail->next = entry; + que->tail = que->tail->next; + } + return 1; +} + +static IARTN_Q * ia_deque_rtn_q (IARTN_Q *que) { + IARTN_Q *tmpdata; + if (que->next == NULL) + return NULL; + tmpdata = que->next; + if ( que->next == que->tail) + que->next = que->tail = NULL; + else + que->next = que->next->next; + return tmpdata; +} + +static void ia_hack_tcq(IADEV *dev) { + + u_short desc1; + u_short tcq_wr; + struct ia_vcc *iavcc_r = NULL; + extern void desc_dbg(IADEV *iadev); + + tcq_wr = readl(dev->seg_reg+TCQ_WR_PTR) & 0xffff; + while (dev->host_tcq_wr != tcq_wr) { + desc1 = *(u_short *)(dev->seg_ram + dev->host_tcq_wr); + if (!desc1) ; + else if (!dev->desc_tbl[desc1 -1].timestamp) { + IF_ABR(printk(" Desc %d is reset at %ld\n", desc1 -1, jiffies);) + *(u_short *) (dev->seg_ram + dev->host_tcq_wr) = 0; + } + else if (dev->desc_tbl[desc1 -1].timestamp) { + if (!(iavcc_r = dev->desc_tbl[desc1 -1].iavcc)) { + printk("IA: Fatal err in get_desc\n"); + continue; + } + iavcc_r->vc_desc_cnt--; + dev->desc_tbl[desc1 -1].timestamp = 0; + IF_EVENT(printk("ia_hack: return_q skb = 0x%x desc = %d\n", + (u32)dev->desc_tbl[desc1 -1].txskb, desc1);) + if (iavcc_r->pcr < dev->rate_limit) { + IA_SKB_STATE (dev->desc_tbl[desc1-1].txskb) |= IA_TX_DONE; + if (ia_enque_rtn_q(&dev->tx_return_q, dev->desc_tbl[desc1 -1]) < 0) + printk("ia_hack_tcq: No memory available\n"); + } + dev->desc_tbl[desc1 -1].iavcc = NULL; + dev->desc_tbl[desc1 -1].txskb = NULL; + } + dev->host_tcq_wr += 2; + if (dev->host_tcq_wr > dev->ffL.tcq_ed) + dev->host_tcq_wr = dev->ffL.tcq_st; + } +} /* ia_hack_tcq */ + +static u16 get_desc (IADEV *dev, struct ia_vcc *iavcc) { + u_short desc_num, i; + struct sk_buff *skb; + struct ia_vcc *iavcc_r = NULL; + unsigned long delta; + static unsigned long timer = 0; + int ltimeout; + extern void desc_dbg(IADEV *iadev); + + ia_hack_tcq (dev); + if(((jiffies - timer)>50)||((dev->ffL.tcq_rd==dev->host_tcq_wr))){ + timer = jiffies; + i=0; + while (i < dev->num_tx_desc) { + if (!dev->desc_tbl[i].timestamp) { + i++; + continue; + } + ltimeout = dev->desc_tbl[i].iavcc->ltimeout; + delta = jiffies - dev->desc_tbl[i].timestamp; + if (delta >= ltimeout) { + IF_ABR(printk("RECOVER run!! desc_tbl %d = %d delta = %ld, + time = %ld\n", i,dev->desc_tbl[i].timestamp, delta, jiffies);) + if (dev->ffL.tcq_rd == dev->ffL.tcq_st) + dev->ffL.tcq_rd = dev->ffL.tcq_ed; + else + dev->ffL.tcq_rd -= 2; + *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd) = i+1; + if (!(skb = dev->desc_tbl[i].txskb) || + !(iavcc_r = dev->desc_tbl[i].iavcc)) + printk("Fatal err, desc table vcc or skb is NULL\n"); + else + iavcc_r->vc_desc_cnt--; + dev->desc_tbl[i].timestamp = 0; + dev->desc_tbl[i].iavcc = NULL; + dev->desc_tbl[i].txskb = NULL; + } + i++; + } /* while */ + } + if (dev->ffL.tcq_rd == dev->host_tcq_wr) + return 0xFFFF; + + /* Get the next available descriptor number from TCQ */ + desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd); + + while (!desc_num || (dev->desc_tbl[desc_num -1]).timestamp) { + dev->ffL.tcq_rd += 2; + if (dev->ffL.tcq_rd > dev->ffL.tcq_ed) + dev->ffL.tcq_rd = dev->ffL.tcq_st; + if (dev->ffL.tcq_rd == dev->host_tcq_wr) + return 0xFFFF; + desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd); + } + + /* get system time */ + dev->desc_tbl[desc_num -1].timestamp = jiffies; + return desc_num; +} + +static void clear_lockup (struct atm_vcc *vcc, IADEV *dev) { + u_char foundLockUp; + vcstatus_t *vcstatus; + u_short *shd_tbl; + u_short tempCellSlot, tempFract; + struct main_vc *abr_vc = (struct main_vc *)dev->MAIN_VC_TABLE_ADDR; + struct ext_vc *eabr_vc = (struct ext_vc *)dev->EXT_VC_TABLE_ADDR; + u_int i; + + if (vcc->qos.txtp.traffic_class == ATM_ABR) { + vcstatus = (vcstatus_t *) &(dev->testTable[vcc->vci]->vc_status); + vcstatus->cnt++; + foundLockUp = 0; + if( vcstatus->cnt == 0x05 ) { + abr_vc += vcc->vci; + eabr_vc += vcc->vci; + if( eabr_vc->last_desc ) { + if( (abr_vc->status & 0x07) == ABR_STATE /* 0x2 */ ) { + /* Wait for 10 Micro sec */ + udelay(10); + if ((eabr_vc->last_desc)&&((abr_vc->status & 0x07)==ABR_STATE)) + foundLockUp = 1; + } + else { + tempCellSlot = abr_vc->last_cell_slot; + tempFract = abr_vc->fraction; + if((tempCellSlot == dev->testTable[vcc->vci]->lastTime) + && (tempFract == dev->testTable[vcc->vci]->fract)) + foundLockUp = 1; + dev->testTable[vcc->vci]->lastTime = tempCellSlot; + dev->testTable[vcc->vci]->fract = tempFract; + } + } /* last descriptor */ + vcstatus->cnt = 0; + } /* vcstatus->cnt */ + + if (foundLockUp) { + IF_ABR(printk("LOCK UP found\n");) + writew(0xFFFD, dev->seg_reg+MODE_REG_0); + /* Wait for 10 Micro sec */ + udelay(10); + abr_vc->status &= 0xFFF8; + abr_vc->status |= 0x0001; /* state is idle */ + shd_tbl = (u_short *)dev->ABR_SCHED_TABLE_ADDR; + for( i = 0; ((i < dev->num_vc) && (shd_tbl[i])); i++ ); + if (i < dev->num_vc) + shd_tbl[i] = vcc->vci; + else + IF_ERR(printk("ABR Seg. may not continue on VC %x\n",vcc->vci);) + writew(T_ONLINE, dev->seg_reg+MODE_REG_0); + writew(~(TRANSMIT_DONE|TCQ_NOT_EMPTY), dev->seg_reg+SEG_MASK_REG); + writew(TRANSMIT_DONE, dev->seg_reg+SEG_INTR_STATUS_REG); + vcstatus->cnt = 0; + } /* foundLockUp */ + + } /* if an ABR VC */ + + +} + +/* +** Conversion of 24-bit cellrate (cells/sec) to 16-bit floating point format. +** +** +----+----+------------------+-------------------------------+ +** | R | NZ | 5-bit exponent | 9-bit mantissa | +** +----+----+------------------+-------------------------------+ +** +** R = reserverd (written as 0) +** NZ = 0 if 0 cells/sec; 1 otherwise +** +** if NZ = 1, rate = 1.mmmmmmmmm x 2^(eeeee) cells/sec +*/ +static u16 +cellrate_to_float(u32 cr) +{ + +#define NZ 0x4000 +#define M_BITS 9 /* Number of bits in mantissa */ +#define E_BITS 5 /* Number of bits in exponent */ +#define M_MASK 0x1ff +#define E_MASK 0x1f + u16 flot; + u32 tmp = cr & 0x00ffffff; + int i = 0; + if (cr == 0) + return 0; + while (tmp != 1) { + tmp >>= 1; + i++; + } + if (i == M_BITS) + flot = NZ | (i << M_BITS) | (cr & M_MASK); + else if (i < M_BITS) + flot = NZ | (i << M_BITS) | ((cr << (M_BITS - i)) & M_MASK); + else + flot = NZ | (i << M_BITS) | ((cr >> (i - M_BITS)) & M_MASK); + return flot; +} + +#if 0 +/* +** Conversion of 16-bit floating point format to 24-bit cellrate (cells/sec). +*/ +static u32 +float_to_cellrate(u16 rate) +{ + u32 exp, mantissa, cps; + if ((rate & NZ) == 0) + return 0; + exp = (rate >> M_BITS) & E_MASK; + mantissa = rate & M_MASK; + if (exp == 0) + return 1; + cps = (1 << M_BITS) | mantissa; + if (exp == M_BITS) + cps = cps; + else if (exp > M_BITS) + cps <<= (exp - M_BITS); + else + cps >>= (M_BITS - exp); + return cps; +} +#endif + +static void init_abr_vc (IADEV *dev, srv_cls_param_t *srv_p) { + srv_p->class_type = ATM_ABR; + srv_p->pcr = dev->LineRate; + srv_p->mcr = 0; + srv_p->icr = 0x055cb7; + srv_p->tbe = 0xffffff; + srv_p->frtt = 0x3a; + srv_p->rif = 0xf; + srv_p->rdf = 0xb; + srv_p->nrm = 0x4; + srv_p->trm = 0x7; + srv_p->cdf = 0x3; + srv_p->adtf = 50; +} + +static int +ia_open_abr_vc(IADEV *dev, srv_cls_param_t *srv_p, + struct atm_vcc *vcc, u8 flag) +{ + f_vc_abr_entry *f_abr_vc; + r_vc_abr_entry *r_abr_vc; + u32 icr; + u8 trm, nrm, crm; + u16 adtf, air, *ptr16; + f_abr_vc =(f_vc_abr_entry *)dev->MAIN_VC_TABLE_ADDR; + f_abr_vc += vcc->vci; + switch (flag) { + case 1: /* FFRED initialization */ +#if 0 /* sanity check */ + if (srv_p->pcr == 0) + return INVALID_PCR; + if (srv_p->pcr > dev->LineRate) + srv_p->pcr = dev->LineRate; + if ((srv_p->mcr + dev->sum_mcr) > dev->LineRate) + return MCR_UNAVAILABLE; + if (srv_p->mcr > srv_p->pcr) + return INVALID_MCR; + if (!(srv_p->icr)) + srv_p->icr = srv_p->pcr; + if ((srv_p->icr < srv_p->mcr) || (srv_p->icr > srv_p->pcr)) + return INVALID_ICR; + if ((srv_p->tbe < MIN_TBE) || (srv_p->tbe > MAX_TBE)) + return INVALID_TBE; + if ((srv_p->frtt < MIN_FRTT) || (srv_p->frtt > MAX_FRTT)) + return INVALID_FRTT; + if (srv_p->nrm > MAX_NRM) + return INVALID_NRM; + if (srv_p->trm > MAX_TRM) + return INVALID_TRM; + if (srv_p->adtf > MAX_ADTF) + return INVALID_ADTF; + else if (srv_p->adtf == 0) + srv_p->adtf = 1; + if (srv_p->cdf > MAX_CDF) + return INVALID_CDF; + if (srv_p->rif > MAX_RIF) + return INVALID_RIF; + if (srv_p->rdf > MAX_RDF) + return INVALID_RDF; +#endif + memset ((caddr_t)f_abr_vc, 0, sizeof(f_vc_abr_entry)); + f_abr_vc->f_vc_type = ABR; + nrm = 2 << srv_p->nrm; /* (2 ** (srv_p->nrm +1)) */ + /* i.e 2**n = 2 << (n-1) */ + f_abr_vc->f_nrm = nrm << 8 | nrm; + trm = 100000/(2 << (16 - srv_p->trm)); + if ( trm == 0) trm = 1; + f_abr_vc->f_nrmexp =(((srv_p->nrm +1) & 0x0f) << 12)|(MRM << 8) | trm; + crm = srv_p->tbe / nrm; + if (crm == 0) crm = 1; + f_abr_vc->f_crm = crm & 0xff; + f_abr_vc->f_pcr = cellrate_to_float(srv_p->pcr); + icr = MIN( srv_p->icr, (srv_p->tbe > srv_p->frtt) ? + ((srv_p->tbe/srv_p->frtt)*1000000) : + (1000000/(srv_p->frtt/srv_p->tbe))); + f_abr_vc->f_icr = cellrate_to_float(icr); + adtf = (10000 * srv_p->adtf)/8192; + if (adtf == 0) adtf = 1; + f_abr_vc->f_cdf = ((7 - srv_p->cdf) << 12 | adtf) & 0xfff; + f_abr_vc->f_mcr = cellrate_to_float(srv_p->mcr); + f_abr_vc->f_acr = f_abr_vc->f_icr; + f_abr_vc->f_status = 0x0042; + break; + case 0: /* RFRED initialization */ + ptr16 = (u_short *)(dev->reass_ram + REASS_TABLE*dev->memSize); + *(ptr16 + vcc->vci) = NO_AAL5_PKT | REASS_ABR; + r_abr_vc = (r_vc_abr_entry*)(dev->reass_ram+ABR_VC_TABLE*dev->memSize); + r_abr_vc += vcc->vci; + r_abr_vc->r_status_rdf = (15 - srv_p->rdf) & 0x000f; + air = srv_p->pcr << (15 - srv_p->rif); + if (air == 0) air = 1; + r_abr_vc->r_air = cellrate_to_float(air); + dev->testTable[vcc->vci]->vc_status = VC_ACTIVE | VC_ABR; + dev->sum_mcr += srv_p->mcr; + dev->n_abr++; + break; + default: + break; + } + return 0; +} +static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) { + u32 rateLow=0, rateHigh, rate; + int entries; + struct ia_vcc *ia_vcc; + + int idealSlot =0, testSlot, toBeAssigned, inc; + u32 spacing; + u16 *SchedTbl, *TstSchedTbl; + u16 cbrVC, vcIndex; + u32 fracSlot = 0; + u32 sp_mod = 0; + u32 sp_mod2 = 0; + + /* IpAdjustTrafficParams */ + if (vcc->qos.txtp.max_pcr <= 0) { + IF_ERR(printk("PCR for CBR not defined\n");) + return -1; + } + rate = vcc->qos.txtp.max_pcr; + entries = rate / dev->Granularity; + IF_CBR(printk("CBR: CBR entries=0x%x for rate=0x%x & Gran=0x%x\n", + entries, rate, dev->Granularity);) + if (entries < 1) + IF_CBR(printk("CBR: Bandwidth smaller than granularity of CBR table\n");) + rateLow = entries * dev->Granularity; + rateHigh = (entries + 1) * dev->Granularity; + if (3*(rate - rateLow) > (rateHigh - rate)) + entries++; + if (entries > dev->CbrRemEntries) { + IF_CBR(printk("CBR: Not enough bandwidth to support this PCR.\n");) + IF_CBR(printk("Entries = 0x%x, CbrRemEntries = 0x%x.\n", + entries, dev->CbrRemEntries);) + return -EBUSY; + } + + ia_vcc = INPH_IA_VCC(vcc); + ia_vcc->NumCbrEntry = entries; + dev->sum_mcr += entries * dev->Granularity; + /* IaFFrednInsertCbrSched */ + // Starting at an arbitrary location, place the entries into the table + // as smoothly as possible + cbrVC = 0; + spacing = dev->CbrTotEntries / entries; + sp_mod = dev->CbrTotEntries % entries; // get modulo + toBeAssigned = entries; + fracSlot = 0; + vcIndex = vcc->vci; + IF_CBR(printk("Vci=0x%x,Spacing=0x%x,Sp_mod=0x%x\n",vcIndex,spacing,sp_mod);) + while (toBeAssigned) + { + // If this is the first time, start the table loading for this connection + // as close to entryPoint as possible. + if (toBeAssigned == entries) + { + idealSlot = dev->CbrEntryPt; + dev->CbrEntryPt += 2; // Adding 2 helps to prevent clumping + if (dev->CbrEntryPt >= dev->CbrTotEntries) + dev->CbrEntryPt -= dev->CbrTotEntries;// Wrap if necessary + } else { + idealSlot += (u32)(spacing + fracSlot); // Point to the next location + // in the table that would be smoothest + fracSlot = ((sp_mod + sp_mod2) / entries); // get new integer part + sp_mod2 = ((sp_mod + sp_mod2) % entries); // calc new fractional part + } + if (idealSlot >= (int)dev->CbrTotEntries) + idealSlot -= dev->CbrTotEntries; + // Continuously check around this ideal value until a null + // location is encountered. + SchedTbl = (u16*)(dev->seg_ram+CBR_SCHED_TABLE*dev->memSize); + inc = 0; + testSlot = idealSlot; + TstSchedTbl = (u16*)(SchedTbl+testSlot); //set index and read in value + IF_CBR(printk("CBR Testslot 0x%x AT Location 0x%x, NumToAssign=%d\n", + testSlot, (u32)TstSchedTbl,toBeAssigned);) + memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16)); + while (cbrVC) // If another VC at this location, we have to keep looking + { + inc++; + testSlot = idealSlot - inc; + if (testSlot < 0) { // Wrap if necessary + testSlot += dev->CbrTotEntries; + IF_CBR(printk("Testslot Wrap. STable Start=0x%x,Testslot=%d\n", + (u32)SchedTbl,testSlot);) + } + TstSchedTbl = (u16 *)(SchedTbl + testSlot); // set table index + memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16)); + if (!cbrVC) + break; + testSlot = idealSlot + inc; + if (testSlot >= (int)dev->CbrTotEntries) { // Wrap if necessary + testSlot -= dev->CbrTotEntries; + IF_CBR(printk("TotCbrEntries=%d",dev->CbrTotEntries);) + IF_CBR(printk(" Testslot=0x%x ToBeAssgned=%d\n", + testSlot, toBeAssigned);) + } + // set table index and read in value + TstSchedTbl = (u16*)(SchedTbl + testSlot); + IF_CBR(printk("Reading CBR Tbl from 0x%x, CbrVal=0x%x Iteration %d\n", + (u32)TstSchedTbl,cbrVC,inc);) + memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(u16)); + } /* while */ + // Move this VCI number into this location of the CBR Sched table. + memcpy((caddr_t)TstSchedTbl, (caddr_t)&vcIndex,sizeof(u16)); + dev->CbrRemEntries--; + toBeAssigned--; + } /* while */ + + /* IaFFrednCbrEnable */ + dev->NumEnabledCBR++; + if (dev->NumEnabledCBR == 1) { + writew((CBR_EN | UBR_EN | ABR_EN | (0x23 << 2)), dev->seg_reg+STPARMS); + IF_CBR(printk("CBR is enabled\n");) + } + return 0; +} +static void ia_cbrVc_close (struct atm_vcc *vcc) { + IADEV *iadev; + u16 *SchedTbl, NullVci = 0; + u32 i, NumFound; + + iadev = INPH_IA_DEV(vcc->dev); + iadev->NumEnabledCBR--; + SchedTbl = (u16*)(iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize); + if (iadev->NumEnabledCBR == 0) { + writew((UBR_EN | ABR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); + IF_CBR (printk("CBR support disabled\n");) + } + NumFound = 0; + for (i=0; i < iadev->CbrTotEntries; i++) + { + if (*SchedTbl == vcc->vci) { + iadev->CbrRemEntries++; + *SchedTbl = NullVci; + IF_CBR(NumFound++;) + } + SchedTbl++; + } + IF_CBR(printk("Exit ia_cbrVc_close, NumRemoved=%d\n",NumFound);) +} + +static int ia_avail_descs(IADEV *iadev) { + int tmp = 0; + ia_hack_tcq(iadev); + if (iadev->host_tcq_wr >= iadev->ffL.tcq_rd) + tmp = (iadev->host_tcq_wr - iadev->ffL.tcq_rd) / 2; + else + tmp = (iadev->ffL.tcq_ed - iadev->ffL.tcq_rd + 2 + iadev->host_tcq_wr - + iadev->ffL.tcq_st) / 2; + return tmp; +} + +static int ia_que_tx (IADEV *iadev) { + struct sk_buff *skb; + int num_desc; + struct atm_vcc *vcc; + struct ia_vcc *iavcc; + static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb); + num_desc = ia_avail_descs(iadev); + while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) { + if (!(vcc = ATM_SKB(skb)->vcc)) { + dev_kfree_skb(skb); + printk("ia_que_tx: Null vcc\n"); + break; + } + if ((vcc->flags & ATM_VF_READY) == 0 ) { + dev_kfree_skb(skb); + printk("Free the SKB on closed vci %d \n", vcc->vci); + break; + } + iavcc = INPH_IA_VCC(vcc); + if (ia_pkt_tx (vcc, skb)) { + skb_queue_head(&iadev->tx_backlog, skb); + } + num_desc--; + } + return 0; +} +void ia_tx_poll (IADEV *iadev) { + struct atm_vcc *vcc = NULL; + struct sk_buff *skb = NULL, *skb1 = NULL; + struct ia_vcc *iavcc; + IARTN_Q * rtne; + + ia_hack_tcq(iadev); + while ( (rtne = ia_deque_rtn_q(&iadev->tx_return_q))) { + skb = rtne->data.txskb; + if (!skb) { + printk("ia_tx_poll: skb is null\n"); + return; + } + vcc = ATM_SKB(skb)->vcc; + if (!vcc) { + printk("ia_tx_poll: vcc is null\n"); + dev_kfree_skb(skb); + return; + } + + iavcc = INPH_IA_VCC(vcc); + if (!iavcc) { + printk("ia_tx_poll: iavcc is null\n"); + dev_kfree_skb(skb); + return; + } + + skb1 = skb_dequeue(&iavcc->txing_skb); + while (skb1 && (skb1 != skb)) { + if (!(IA_SKB_STATE(skb1) & IA_TX_DONE)) { + printk("IA_tx_intr: Vci %d lost pkt!!!\n", vcc->vci); + } + IF_ERR(printk("Release the SKB not match\n");) + if (vcc && (vcc->pop) && (skb1->len != 0)) + { + vcc->pop(vcc, skb1); + IF_EVENT(printk("Tansmit Done - skb 0x%lx return\n", + (long)skb1);) + } + else + dev_kfree_skb(skb1); + skb1 = skb_dequeue(&iavcc->txing_skb); + } + if (!skb1) { + IF_EVENT(printk("IA: Vci %d - skb not found requed\n",vcc->vci);) + ia_enque_head_rtn_q (&iadev->tx_return_q, rtne); + break; + } + if (vcc && (vcc->pop) && (skb->len != 0)) + { + vcc->pop(vcc, skb); + IF_EVENT(printk("Tx Done - skb 0x%lx return\n",(long)skb);) + } + else + dev_kfree_skb(skb); + kfree(rtne); + } + ia_que_tx(iadev); + return; +} +#if 0 +static void ia_eeprom_put (IADEV *iadev, u32 addr, u_short val) +{ + u32 t; + int i; + /* + * Issue a command to enable writes to the NOVRAM + */ + NVRAM_CMD (EXTEND + EWEN); + NVRAM_CLR_CE; + /* + * issue the write command + */ + NVRAM_CMD(IAWRITE + addr); + /* + * Send the data, starting with D15, then D14, and so on for 16 bits + */ + for (i=15; i>=0; i--) { + NVRAM_CLKOUT (val & 0x8000); + val <<= 1; + } + NVRAM_CLR_CE; + CFG_OR(NVCE); + t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); + while (!(t & NVDO)) + t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); + + NVRAM_CLR_CE; + /* + * disable writes again + */ + NVRAM_CMD(EXTEND + EWDS) + NVRAM_CLR_CE; + CFG_AND(~NVDI); +} +#endif + +static u16 ia_eeprom_get (IADEV *iadev, u32 addr) +{ + u_short val; + u32 t; + int i; + /* + * Read the first bit that was clocked with the falling edge of the + * the last command data clock + */ + NVRAM_CMD(IAREAD + addr); + /* + * Now read the rest of the bits, the next bit read is D14, then D13, + * and so on. + */ + val = 0; + for (i=15; i>=0; i--) { + NVRAM_CLKIN(t); + val |= (t << i); + } + NVRAM_CLR_CE; + CFG_AND(~NVDI); + return val; +} + +static void ia_hw_type(IADEV *iadev) { + u_short memType = ia_eeprom_get(iadev, 25); + iadev->memType = memType; + if ((memType & MEM_SIZE_MASK) == MEM_SIZE_1M) { + iadev->num_tx_desc = IA_TX_BUF; + iadev->tx_buf_sz = IA_TX_BUF_SZ; + iadev->num_rx_desc = IA_RX_BUF; + iadev->rx_buf_sz = IA_RX_BUF_SZ; + } else if ((memType & MEM_SIZE_MASK) == MEM_SIZE_512K) { + if (IA_TX_BUF == DFL_TX_BUFFERS) + iadev->num_tx_desc = IA_TX_BUF / 2; + else + iadev->num_tx_desc = IA_TX_BUF; + iadev->tx_buf_sz = IA_TX_BUF_SZ; + if (IA_RX_BUF == DFL_RX_BUFFERS) + iadev->num_rx_desc = IA_RX_BUF / 2; + else + iadev->num_rx_desc = IA_RX_BUF; + iadev->rx_buf_sz = IA_RX_BUF_SZ; + } + else { + if (IA_TX_BUF == DFL_TX_BUFFERS) + iadev->num_tx_desc = IA_TX_BUF / 8; + else + iadev->num_tx_desc = IA_TX_BUF; + iadev->tx_buf_sz = IA_TX_BUF_SZ; + if (IA_RX_BUF == DFL_RX_BUFFERS) + iadev->num_rx_desc = IA_RX_BUF / 8; + else + iadev->num_rx_desc = IA_RX_BUF; + iadev->rx_buf_sz = IA_RX_BUF_SZ; + } + iadev->rx_pkt_ram = TX_PACKET_RAM + (iadev->num_tx_desc * iadev->tx_buf_sz); + IF_INIT(printk("BUF: tx=%d,sz=%d rx=%d sz= %d rx_pkt_ram=%d\n", + iadev->num_tx_desc, iadev->tx_buf_sz, iadev->num_rx_desc, + iadev->rx_buf_sz, iadev->rx_pkt_ram);) + +#if 0 + if ((memType & FE_MASK) == FE_SINGLE_MODE) { + iadev->phy_type = PHY_OC3C_S; + else if ((memType & FE_MASK) == FE_UTP_OPTION) + iadev->phy_type = PHY_UTP155; + else + iadev->phy_type = PHY_OC3C_M; +#endif + + iadev->phy_type = memType & FE_MASK; + IF_INIT(printk("memType = 0x%x iadev->phy_type = 0x%x\n", + memType,iadev->phy_type);) + if (iadev->phy_type == FE_25MBIT_PHY) + iadev->LineRate = (u32)(((25600000/8)*26)/(27*53)); + else if (iadev->phy_type == FE_DS3_PHY) + iadev->LineRate = (u32)(((44736000/8)*26)/(27*53)); + else if (iadev->phy_type == FE_E3_PHY) + iadev->LineRate = (u32)(((34368000/8)*26)/(27*53)); + else + iadev->LineRate = (u32)(ATM_OC3_PCR); + IF_INIT(printk("iadev->LineRate = %d \n", iadev->LineRate);) + +} + +static void IaFrontEndIntr(IADEV *iadev) { + volatile IA_SUNI *suni; + volatile ia_mb25_t *mb25; + volatile suni_pm7345_t *suni_pm7345; + u32 intr_status; + u_int frmr_intr; + + if(iadev->phy_type & FE_25MBIT_PHY) { + mb25 = (ia_mb25_t*)iadev->phy; + iadev->carrier_detect = Boolean(mb25->mb25_intr_status & MB25_IS_GSB); + } else if (iadev->phy_type & FE_DS3_PHY) { + suni_pm7345 = (suni_pm7345_t *)iadev->phy; + /* clear FRMR interrupts */ + frmr_intr = suni_pm7345->suni_ds3_frm_intr_stat; + iadev->carrier_detect = + Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV)); + } else if (iadev->phy_type & FE_E3_PHY ) { + suni_pm7345 = (suni_pm7345_t *)iadev->phy; + frmr_intr = suni_pm7345->suni_e3_frm_maint_intr_ind; + iadev->carrier_detect = + Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat&SUNI_E3_LOS)); + } + else { + suni = (IA_SUNI *)iadev->phy; + intr_status = suni->suni_rsop_status & 0xff; + iadev->carrier_detect = Boolean(!(suni->suni_rsop_status & SUNI_LOSV)); + } + if (iadev->carrier_detect) + printk("IA: SUNI carrier detected\n"); + else + printk("IA: SUNI carrier lost signal\n"); + return; +} + +void ia_mb25_init (IADEV *iadev) +{ + volatile ia_mb25_t *mb25 = (ia_mb25_t*)iadev->phy; +#if 0 + mb25->mb25_master_ctrl = MB25_MC_DRIC | MB25_MC_DREC | MB25_MC_ENABLED; +#endif + mb25->mb25_master_ctrl = MB25_MC_DRIC | MB25_MC_DREC; + mb25->mb25_diag_control = 0; + /* + * Initialize carrier detect state + */ + iadev->carrier_detect = Boolean(mb25->mb25_intr_status & MB25_IS_GSB); + return; +} + +void ia_suni_pm7345_init (IADEV *iadev) +{ + volatile suni_pm7345_t *suni_pm7345 = (suni_pm7345_t *)iadev->phy; + if (iadev->phy_type & FE_DS3_PHY) + { + iadev->carrier_detect = + Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV)); + suni_pm7345->suni_ds3_frm_intr_enbl = 0x17; + suni_pm7345->suni_ds3_frm_cfg = 1; + suni_pm7345->suni_ds3_tran_cfg = 1; + suni_pm7345->suni_config = 0; + suni_pm7345->suni_splr_cfg = 0; + suni_pm7345->suni_splt_cfg = 0; + } + else + { + iadev->carrier_detect = + Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat & SUNI_E3_LOS)); + suni_pm7345->suni_e3_frm_fram_options = 0x4; + suni_pm7345->suni_e3_frm_maint_options = 0x20; + suni_pm7345->suni_e3_frm_fram_intr_enbl = 0x1d; + suni_pm7345->suni_e3_frm_maint_intr_enbl = 0x30; + suni_pm7345->suni_e3_tran_stat_diag_options = 0x0; + suni_pm7345->suni_e3_tran_fram_options = 0x1; + suni_pm7345->suni_config = SUNI_PM7345_E3ENBL; + suni_pm7345->suni_splr_cfg = 0x41; + suni_pm7345->suni_splt_cfg = 0x41; + } + /* + * Enable RSOP loss of signal interrupt. + */ + suni_pm7345->suni_intr_enbl = 0x28; + + /* + * Clear error counters + */ + suni_pm7345->suni_id_reset = 0; + + /* + * Clear "PMCTST" in master test register. + */ + suni_pm7345->suni_master_test = 0; + + suni_pm7345->suni_rxcp_ctrl = 0x2c; + suni_pm7345->suni_rxcp_fctrl = 0x81; + + suni_pm7345->suni_rxcp_idle_pat_h1 = 0; + suni_pm7345->suni_rxcp_idle_pat_h2 = 0; + suni_pm7345->suni_rxcp_idle_pat_h3 = 0; + suni_pm7345->suni_rxcp_idle_pat_h4 = 1; + + suni_pm7345->suni_rxcp_idle_mask_h1 = 0xff; + suni_pm7345->suni_rxcp_idle_mask_h2 = 0xff; + suni_pm7345->suni_rxcp_idle_mask_h3 = 0xff; + suni_pm7345->suni_rxcp_idle_mask_h4 = 0xfe; + + suni_pm7345->suni_rxcp_cell_pat_h1 = 0; + suni_pm7345->suni_rxcp_cell_pat_h2 = 0; + suni_pm7345->suni_rxcp_cell_pat_h3 = 0; + suni_pm7345->suni_rxcp_cell_pat_h4 = 1; + + suni_pm7345->suni_rxcp_cell_mask_h1 = 0xff; + suni_pm7345->suni_rxcp_cell_mask_h2 = 0xff; + suni_pm7345->suni_rxcp_cell_mask_h3 = 0xff; + suni_pm7345->suni_rxcp_cell_mask_h4 = 0xff; + + suni_pm7345->suni_txcp_ctrl = 0xa4; + suni_pm7345->suni_txcp_intr_en_sts = 0x10; + suni_pm7345->suni_txcp_idle_pat_h5 = 0x55; + + suni_pm7345->suni_config &= ~(SUNI_PM7345_LLB | + SUNI_PM7345_CLB | + SUNI_PM7345_DLB | + SUNI_PM7345_PLB); +#ifdef __SNMP__ + suni_pm7345->suni_rxcp_intr_en_sts |= SUNI_OOCDE; +#endif __SNMP__ + return; +} + + +/***************************** IA_LIB END *****************************/ + +/* pwang_test debug utility */ +int tcnter = 0, rcnter = 0; +void xdump( u_char* cp, int length, char* prefix ) +{ + int col, count; + u_char prntBuf[120]; + u_char* pBuf = prntBuf; + count = 0; + while(count < length){ + pBuf += sprintf( pBuf, "%s", prefix ); + for(col = 0;count + col < length && col < 16; col++){ + if (col != 0 && (col % 4) == 0) + pBuf += sprintf( pBuf, " " ); + pBuf += sprintf( pBuf, "%02X ", cp[count + col] ); + } + while(col++ < 16){ /* pad end of buffer with blanks */ + if ((col % 4) == 0) + sprintf( pBuf, " " ); + pBuf += sprintf( pBuf, " " ); + } + pBuf += sprintf( pBuf, " " ); + for(col = 0;count + col < length && col < 16; col++){ + if (isprint((int)cp[count + col])) + pBuf += sprintf( pBuf, "%c", cp[count + col] ); + else + pBuf += sprintf( pBuf, "." ); + } + sprintf( pBuf, "\n" ); + // SPrint(prntBuf); + printk(prntBuf); + count += col; + pBuf = prntBuf; + } + +} /* close xdump(... */ + + +static struct atm_dev *ia_boards = NULL; + +#define ACTUAL_RAM_BASE \ + RAM_BASE*((iadev->mem)/(128 * 1024)) +#define ACTUAL_SEG_RAM_BASE \ + IPHASE5575_FRAG_CONTROL_RAM_BASE*((iadev->mem)/(128 * 1024)) +#define ACTUAL_REASS_RAM_BASE \ + IPHASE5575_REASS_CONTROL_RAM_BASE*((iadev->mem)/(128 * 1024)) + + +/*-- some utilities and memory allocation stuff will come here -------------*/ + +void desc_dbg(IADEV *iadev) { + + u_short tcq_wr_ptr, tcq_st_ptr, tcq_ed_ptr; + u32 tmp, i; + // regval = readl((u32)ia_cmds->maddr); + tcq_wr_ptr = readw(iadev->seg_reg+TCQ_WR_PTR); + printk("B_tcq_wr = 0x%x desc = %d last desc = %d\n", + tcq_wr_ptr, readw(iadev->seg_ram+tcq_wr_ptr), + readw(iadev->seg_ram+tcq_wr_ptr-2)); + printk(" host_tcq_wr = 0x%x host_tcq_rd = 0x%x \n", iadev->host_tcq_wr, + iadev->ffL.tcq_rd); + tcq_st_ptr = readw(iadev->seg_reg+TCQ_ST_ADR); + tcq_ed_ptr = readw(iadev->seg_reg+TCQ_ED_ADR); + printk("tcq_st_ptr = 0x%x tcq_ed_ptr = 0x%x \n", tcq_st_ptr, tcq_ed_ptr); + i = 0; + while (tcq_st_ptr != tcq_ed_ptr) { + tmp = iadev->seg_ram+tcq_st_ptr; + printk("TCQ slot %d desc = %d Addr = 0x%x\n", i++, readw(tmp), tmp); + tcq_st_ptr += 2; + } + for(i=0; i num_tx_desc; i++) + printk("Desc_tbl[%d] = %d \n", i, iadev->desc_tbl[i].timestamp); +} + + +/*----------------------------- Recieving side stuff --------------------------*/ + +static void rx_excp_rcvd(struct atm_dev *dev) +{ +#if 0 /* closing the receiving size will cause too many excp int */ + IADEV *iadev; + u_short state; + u_short excpq_rd_ptr; + //u_short *ptr; + int vci, error = 1; + iadev = INPH_IA_DEV(dev); + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + while((state & EXCPQ_EMPTY) != EXCPQ_EMPTY) + { printk("state = %x \n", state); + excpq_rd_ptr = readw(iadev->reass_reg + EXCP_Q_RD_PTR) & 0xffff; + printk("state = %x excpq_rd_ptr = %x \n", state, excpq_rd_ptr); + if (excpq_rd_ptr == *(u16*)(iadev->reass_reg + EXCP_Q_WR_PTR)) + IF_ERR(printk("excpq_rd_ptr is wrong!!!\n");) + // TODO: update exception stat + vci = readw(iadev->reass_ram+excpq_rd_ptr); + error = readw(iadev->reass_ram+excpq_rd_ptr+2) & 0x0007; + // pwang_test + excpq_rd_ptr += 4; + if (excpq_rd_ptr > (readw(iadev->reass_reg + EXCP_Q_ED_ADR)& 0xffff)) + excpq_rd_ptr = readw(iadev->reass_reg + EXCP_Q_ST_ADR)& 0xffff; + writew( excpq_rd_ptr, iadev->reass_reg + EXCP_Q_RD_PTR); + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + } +#endif +} + +static void free_desc(struct atm_dev *dev, int desc) +{ + IADEV *iadev; + iadev = INPH_IA_DEV(dev); + writew(desc, iadev->reass_ram+iadev->rfL.fdq_wr); + iadev->rfL.fdq_wr +=2; + if (iadev->rfL.fdq_wr > iadev->rfL.fdq_ed) + iadev->rfL.fdq_wr = iadev->rfL.fdq_st; + writew(iadev->rfL.fdq_wr, iadev->reass_reg+FREEQ_WR_PTR); +} + + +static int rx_pkt(struct atm_dev *dev) +{ + IADEV *iadev; + struct atm_vcc *vcc; + unsigned short status; + struct rx_buf_desc *buf_desc_ptr; + int desc; + struct dle* wr_ptr; + int len; + struct sk_buff *skb; + u_int buf_addr, dma_addr; + iadev = INPH_IA_DEV(dev); + if (iadev->rfL.pcq_rd == (readw(iadev->reass_reg+PCQ_WR_PTR)&0xffff)) + { + printk(KERN_ERR DEV_LABEL "(itf %d) Receive queue empty\n", dev->number); + return -EINVAL; + } + /* mask 1st 3 bits to get the actual descno. */ + desc = readw(iadev->reass_ram+iadev->rfL.pcq_rd) & 0x1fff; + IF_RX(printk("reass_ram = 0x%x iadev->rfL.pcq_rd = 0x%x desc = %d\n", + iadev->reass_ram, iadev->rfL.pcq_rd, desc); + printk(" pcq_wr_ptr = 0x%x\n", + readw(iadev->reass_reg+PCQ_WR_PTR)&0xffff);) + /* update the read pointer - maybe we shud do this in the end*/ + if ( iadev->rfL.pcq_rd== iadev->rfL.pcq_ed) + iadev->rfL.pcq_rd = iadev->rfL.pcq_st; + else + iadev->rfL.pcq_rd += 2; + writew(iadev->rfL.pcq_rd, iadev->reass_reg+PCQ_RD_PTR); + + /* get the buffer desc entry. + update stuff. - doesn't seem to be any update necessary + */ + buf_desc_ptr = (struct rx_buf_desc *)iadev->RX_DESC_BASE_ADDR; + /* make the ptr point to the corresponding buffer desc entry */ + buf_desc_ptr += desc; + if (!desc || (desc > iadev->num_rx_desc) || + ((buf_desc_ptr->vc_index & 0xffff) > iadev->num_vc)) { + free_desc(dev, desc); + IF_ERR(printk("IA: bad descriptor desc = %d \n", desc);) + return -1; + } + vcc = iadev->rx_open[buf_desc_ptr->vc_index & 0xffff]; + if (!vcc) + { + free_desc(dev, desc); + printk("IA: null vcc, drop PDU\n"); + return -1; + } + + + /* might want to check the status bits for errors */ + status = (u_short) (buf_desc_ptr->desc_mode); + if (status & (RX_CER | RX_PTE | RX_OFL)) + { + vcc->stats->rx_err++; + IF_ERR(printk("IA: bad packet, dropping it");) + if (status & RX_CER) { + IF_ERR(printk(" cause: packet CRC error\n");) + } + else if (status & RX_PTE) { + IF_ERR(printk(" cause: packet time out\n");) + } + else { + IF_ERR(printk(" cause: buffer over flow\n");) + } + free_desc(dev, desc); + return 0; + } + + /* + build DLE. + */ + + buf_addr = (buf_desc_ptr->buf_start_hi << 16) | buf_desc_ptr->buf_start_lo; + dma_addr = (buf_desc_ptr->dma_start_hi << 16) | buf_desc_ptr->dma_start_lo; + len = dma_addr - buf_addr; + if (len > iadev->rx_buf_sz) { + printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz); + vcc->stats->rx_err++; + free_desc(dev, desc); + return 0; + } + +#if LINUX_VERSION_CODE >= 0x20312 + if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) { +#else + if (atm_charge(vcc, atm_pdu2truesize(len))) { + /* lets allocate an skb for now */ + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) + { + IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");) + vcc->stats->rx_drop++; + atm_return(vcc, atm_pdu2truesize(len)); + free_desc(dev, desc); + return 0; + } + } + else { + IF_EVENT(printk("IA: Rx over the rx_quota %ld\n", vcc->rx_quota);) +#endif + if (vcc->vci < 32) + printk("Drop control packets\n"); + free_desc(dev, desc); + return 0; + } + skb_put(skb,len); + // pwang_test + ATM_SKB(skb)->vcc = vcc; + ATM_SKB(skb)->iovcnt = 0; + ATM_DESC(skb) = desc; + skb_queue_tail(&iadev->rx_dma_q, skb); + + /* Build the DLE structure */ + wr_ptr = iadev->rx_dle_q.write; + wr_ptr->sys_pkt_addr = virt_to_bus(skb->data); + wr_ptr->local_pkt_addr = buf_addr; + wr_ptr->bytes = len; /* We don't know this do we ?? */ + wr_ptr->mode = DMA_INT_ENABLE; + + /* shud take care of wrap around here too. */ + if(++wr_ptr == iadev->rx_dle_q.end) + wr_ptr = iadev->rx_dle_q.start; + iadev->rx_dle_q.write = wr_ptr; + udelay(1); + /* Increment transaction counter */ + writel(1, iadev->dma+IPHASE5575_RX_COUNTER); + return 0; +} + +static void rx_intr(struct atm_dev *dev) +{ + IADEV *iadev; + u_short status; + u_short state, i; + + iadev = INPH_IA_DEV(dev); + status = readl(iadev->reass_reg+REASS_INTR_STATUS_REG) & 0xffff; + IF_EVENT(printk("rx_intr: status = 0x%x\n", status);) + if (status & RX_PKT_RCVD) + { + /* do something */ + /* Basically recvd an interrupt for receving a packet. + A descriptor would have been written to the packet complete + queue. Get all the descriptors and set up dma to move the + packets till the packet complete queue is empty.. + */ + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + IF_EVENT(printk("Rx intr status: RX_PKT_RCVD %08x\n", status);) + while(!(state & PCQ_EMPTY)) + { + rx_pkt(dev); + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + } + iadev->rxing = 1; + } + if (status & RX_FREEQ_EMPT) + { + if (iadev->rxing) { + iadev->rx_tmp_cnt = iadev->rx_pkt_cnt; + iadev->rx_tmp_jif = jiffies; + iadev->rxing = 0; + } + else if (((jiffies - iadev->rx_tmp_jif) > 50) && + ((iadev->rx_pkt_cnt - iadev->rx_tmp_cnt) == 0)) { + for (i = 1; i <= iadev->num_rx_desc; i++) + free_desc(dev, i); +printk("Test logic RUN!!!!\n"); + writew( ~(RX_FREEQ_EMPT|RX_EXCP_RCVD),iadev->reass_reg+REASS_MASK_REG); + iadev->rxing = 1; + } + IF_EVENT(printk("Rx intr status: RX_FREEQ_EMPT %08x\n", status);) + } + + if (status & RX_EXCP_RCVD) + { + /* probably need to handle the exception queue also. */ + IF_EVENT(printk("Rx intr status: RX_EXCP_RCVD %08x\n", status);) + rx_excp_rcvd(dev); + } + + + if (status & RX_RAW_RCVD) + { + /* need to handle the raw incoming cells. This deepnds on + whether we have programmed to receive the raw cells or not. + Else ignore. */ + IF_EVENT(printk("Rx intr status: RX_RAW_RCVD %08x\n", status);) + } +} + + +static void rx_dle_intr(struct atm_dev *dev) +{ + IADEV *iadev; + struct atm_vcc *vcc; + struct sk_buff *skb; + int desc; + u_short state; + struct dle *dle, *cur_dle; + u_int dle_lp; + iadev = INPH_IA_DEV(dev); + + /* free all the dles done, that is just update our own dle read pointer + - do we really need to do this. Think not. */ + /* DMA is done, just get all the recevie buffers from the rx dma queue + and push them up to the higher layer protocol. Also free the desc + associated with the buffer. */ + dle = iadev->rx_dle_q.read; + dle_lp = readl(iadev->dma+IPHASE5575_RX_LIST_ADDR) & (sizeof(struct dle)*DLE_ENTRIES - 1); + cur_dle = (struct dle*)(iadev->rx_dle_q.start + (dle_lp >> 4)); + while(dle != cur_dle) + { + /* free the DMAed skb */ + skb = skb_dequeue(&iadev->rx_dma_q); + if (!skb) + goto INCR_DLE; + desc = ATM_DESC(skb); + free_desc(dev, desc); + + if (!skb->len) + { + printk("rx_dle_intr: skb len 0\n"); + dev_kfree_skb(skb); + } + else + { + struct cpcs_trailer *trailer; + u_short length; + struct ia_vcc *ia_vcc; + /* no VCC related housekeeping done as yet. lets see */ + vcc = ATM_SKB(skb)->vcc; + if (!vcc) { + printk("IA: null vcc\n"); + vcc->stats->rx_err++; + dev_kfree_skb(skb); + goto INCR_DLE; + } + ia_vcc = INPH_IA_VCC(vcc); + if (ia_vcc == NULL) + { + vcc->stats->rx_err++; + dev_kfree_skb(skb); +#if LINUX_VERSION_CODE >= 0x20312 + atm_return(vcc, atm_guess_pdu2truesize(skb->len)); +#else + atm_return(vcc, atm_pdu2truesize(skb->len)); +#endif + goto INCR_DLE; + } + // get real pkt length pwang_test + trailer = (struct cpcs_trailer*)((u_char *)skb->data + + skb->len - sizeof(struct cpcs_trailer)); + length = swap(trailer->length); + if ((length > iadev->rx_buf_sz) || (length > + (skb->len - sizeof(struct cpcs_trailer)))) + { + vcc->stats->rx_err++; + dev_kfree_skb(skb); + IF_ERR(printk("rx_dle_intr: Bad AAL5 trailer %d (skb len %d)", + length, skb->len);) +#if LINUX_VERSION_CODE >= 0x20312 + atm_return(vcc, atm_guess_pdu2truesize(skb->len)); +#else + atm_return(vcc, atm_pdu2truesize(skb->len)); +#endif + goto INCR_DLE; + } + skb_trim(skb, length); + + /* Display the packet */ + IF_RXPKT(printk("\nDmad Recvd data: len = %d \n", skb->len); + xdump(skb->data, skb->len, "RX: "); + printk("\n");) + + IF_RX(printk("rx_dle_intr: skb push");) + vcc->push(vcc,skb); + vcc->stats->rx++; + iadev->rx_pkt_cnt++; + } +INCR_DLE: + if (++dle == iadev->rx_dle_q.end) + dle = iadev->rx_dle_q.start; + } + iadev->rx_dle_q.read = dle; + + /* if the interrupts are masked because there were no free desc available, + unmask them now. */ + if (!iadev->rxing) { + state = readl(iadev->reass_reg + STATE_REG) & 0xffff; + if (!(state & FREEQ_EMPTY)) { + state = readl(iadev->reass_reg + REASS_MASK_REG) & 0xffff; + writel(state & ~(RX_FREEQ_EMPT |/* RX_EXCP_RCVD |*/ RX_PKT_RCVD), + iadev->reass_reg+REASS_MASK_REG); + iadev->rxing++; + } + } +} + + +static int open_rx(struct atm_vcc *vcc) +{ + IADEV *iadev; + u_short *vc_table; + u_short *reass_ptr; + IF_EVENT(printk("iadev: open_rx %d.%d\n", vcc->vpi, vcc->vci);) + + if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; + iadev = INPH_IA_DEV(vcc->dev); + if (vcc->qos.rxtp.traffic_class == ATM_ABR) { + if (iadev->phy_type & FE_25MBIT_PHY) { + printk("IA: ABR not support\n"); + return -EINVAL; + } + } + /* Make only this VCI in the vc table valid and let all + others be invalid entries */ + vc_table = (u_short *)(iadev->reass_ram+RX_VC_TABLE*iadev->memSize); + vc_table += vcc->vci; + /* mask the last 6 bits and OR it with 3 for 1K VCs */ + + *vc_table = vcc->vci << 6; + /* Also keep a list of open rx vcs so that we can attach them with + incoming PDUs later. */ + if ((vcc->qos.rxtp.traffic_class == ATM_ABR) || + (vcc->qos.txtp.traffic_class == ATM_ABR)) + { + srv_cls_param_t srv_p; + init_abr_vc(iadev, &srv_p); + ia_open_abr_vc(iadev, &srv_p, vcc, 0); + } + else { /* for UBR later may need to add CBR logic */ + reass_ptr = (u_short *) + (iadev->reass_ram+REASS_TABLE*iadev->memSize); + reass_ptr += vcc->vci; + *reass_ptr = NO_AAL5_PKT; + } + + if (iadev->rx_open[vcc->vci]) + printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d already open\n", + vcc->dev->number, vcc->vci); + iadev->rx_open[vcc->vci] = vcc; + return 0; +} + +static int rx_init(struct atm_dev *dev) +{ + IADEV *iadev; + struct rx_buf_desc *buf_desc_ptr; + unsigned long rx_pkt_start = 0; + u32 *dle_addr; + struct abr_vc_table *abr_vc_table; + u16 *vc_table; + u16 *reass_table; + u16 *ptr16; + int i,j, vcsize_sel; + u_short freeq_st_adr; + u_short *freeq_start; + + iadev = INPH_IA_DEV(dev); + // spin_lock_init(&iadev->rx_lock); + /* I need to initialize the DLEs somewhere. Lets see what I + need to do for this, hmmm... + - allocate memory for 256 DLEs. make sure that it starts + on a 4k byte address boundary. Program the start address + in Receive List address register. ..... to do for TX also + To make sure that it is a 4k byte boundary - allocate 8k and find + 4k byte boundary within. + ( (addr + (4k-1)) & ~(4k-1) ) + */ + + /* allocate 8k bytes */ + dle_addr = (u32*)kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL); + if (!dle_addr) + { + printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n"); + } + /* find 4k byte boundary within the 8k allocated */ + dle_addr = (u32*)( ((u32)dle_addr+(4096-1)) & ~(4096-1) ); + iadev->rx_dle_q.start = (struct dle*)dle_addr; + iadev->rx_dle_q.read = iadev->rx_dle_q.start; + iadev->rx_dle_q.write = iadev->rx_dle_q.start; + iadev->rx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES); + /* the end of the dle q points to the entry after the last + DLE that can be used. */ + + /* write the upper 20 bits of the start address to rx list address register */ + writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_RX_LIST_ADDR); + IF_INIT(printk("Tx Dle list addr: 0x%08x value: 0x%0x\n", + (u32)(iadev->dma+IPHASE5575_TX_LIST_ADDR), + *(u32*)(iadev->dma+IPHASE5575_TX_LIST_ADDR)); + printk("Rx Dle list addr: 0x%08x value: 0x%0x\n", + (u32)(iadev->dma+IPHASE5575_RX_LIST_ADDR), + *(u32*)(iadev->dma+IPHASE5575_RX_LIST_ADDR));) + + writew(0xffff, iadev->reass_reg+REASS_MASK_REG); + writew(0, iadev->reass_reg+MODE_REG); + writew(RESET_REASS, iadev->reass_reg+REASS_COMMAND_REG); + + /* Receive side control memory map + ------------------------------- + + Buffer descr 0x0000 (736 - 23K) + VP Table 0x5c00 (256 - 512) + Except q 0x5e00 (128 - 512) + Free buffer q 0x6000 (1K - 2K) + Packet comp q 0x6800 (1K - 2K) + Reass Table 0x7000 (1K - 2K) + VC Table 0x7800 (1K - 2K) + ABR VC Table 0x8000 (1K - 32K) + */ + + /* Base address for Buffer Descriptor Table */ + writew(RX_DESC_BASE >> 16, iadev->reass_reg+REASS_DESC_BASE); + /* Set the buffer size register */ + writew(iadev->rx_buf_sz, iadev->reass_reg+BUF_SIZE); + + /* Initialize each entry in the Buffer Descriptor Table */ + iadev->RX_DESC_BASE_ADDR = iadev->reass_ram+RX_DESC_BASE*iadev->memSize; + buf_desc_ptr =(struct rx_buf_desc *)iadev->RX_DESC_BASE_ADDR; + memset((caddr_t)buf_desc_ptr, 0, sizeof(struct rx_buf_desc)); + buf_desc_ptr++; + rx_pkt_start = iadev->rx_pkt_ram; + for(i=1; i<=iadev->num_rx_desc; i++) + { + memset((caddr_t)buf_desc_ptr, 0, sizeof(struct rx_buf_desc)); + buf_desc_ptr->buf_start_hi = rx_pkt_start >> 16; + buf_desc_ptr->buf_start_lo = rx_pkt_start & 0x0000ffff; + buf_desc_ptr++; + rx_pkt_start += iadev->rx_buf_sz; + } + IF_INIT(printk("Rx Buffer desc ptr: 0x%0x\n", (u32)(buf_desc_ptr));) + i = FREE_BUF_DESC_Q*iadev->memSize; + writew(i >> 16, iadev->reass_reg+REASS_QUEUE_BASE); + writew(i, iadev->reass_reg+FREEQ_ST_ADR); + writew(i+iadev->num_rx_desc*sizeof(u_short), + iadev->reass_reg+FREEQ_ED_ADR); + writew(i, iadev->reass_reg+FREEQ_RD_PTR); + writew(i+iadev->num_rx_desc*sizeof(u_short), + iadev->reass_reg+FREEQ_WR_PTR); + /* Fill the FREEQ with all the free descriptors. */ + freeq_st_adr = readw(iadev->reass_reg+FREEQ_ST_ADR); + freeq_start = (u_short *)(iadev->reass_ram+freeq_st_adr); + for(i=1; i<=iadev->num_rx_desc; i++) + { + *freeq_start = (u_short)i; + freeq_start++; + } + IF_INIT(printk("freeq_start: 0x%0x\n", (u32)freeq_start);) + /* Packet Complete Queue */ + i = (PKT_COMP_Q * iadev->memSize) & 0xffff; + writew(i, iadev->reass_reg+PCQ_ST_ADR); + writew(i+iadev->num_vc*sizeof(u_short), iadev->reass_reg+PCQ_ED_ADR); + writew(i, iadev->reass_reg+PCQ_RD_PTR); + writew(i, iadev->reass_reg+PCQ_WR_PTR); + + /* Exception Queue */ + i = (EXCEPTION_Q * iadev->memSize) & 0xffff; + writew(i, iadev->reass_reg+EXCP_Q_ST_ADR); + writew(i + NUM_RX_EXCP * sizeof(RX_ERROR_Q), + iadev->reass_reg+EXCP_Q_ED_ADR); + writew(i, iadev->reass_reg+EXCP_Q_RD_PTR); + writew(i, iadev->reass_reg+EXCP_Q_WR_PTR); + + /* Load local copy of FREEQ and PCQ ptrs */ + iadev->rfL.fdq_st = readw(iadev->reass_reg+FREEQ_ST_ADR) & 0xffff; + iadev->rfL.fdq_ed = readw(iadev->reass_reg+FREEQ_ED_ADR) & 0xffff ; + iadev->rfL.fdq_rd = readw(iadev->reass_reg+FREEQ_RD_PTR) & 0xffff; + iadev->rfL.fdq_wr = readw(iadev->reass_reg+FREEQ_WR_PTR) & 0xffff; + iadev->rfL.pcq_st = readw(iadev->reass_reg+PCQ_ST_ADR) & 0xffff; + iadev->rfL.pcq_ed = readw(iadev->reass_reg+PCQ_ED_ADR) & 0xffff; + iadev->rfL.pcq_rd = readw(iadev->reass_reg+PCQ_RD_PTR) & 0xffff; + iadev->rfL.pcq_wr = readw(iadev->reass_reg+PCQ_WR_PTR) & 0xffff; + + IF_INIT(printk("INIT:pcq_st:0x%x pcq_ed:0x%x pcq_rd:0x%x pcq_wr:0x%x", + iadev->rfL.pcq_st, iadev->rfL.pcq_ed, iadev->rfL.pcq_rd, + iadev->rfL.pcq_wr);) + /* just for check - no VP TBL */ + /* VP Table */ + /* writew(0x0b80, iadev->reass_reg+VP_LKUP_BASE); */ + /* initialize VP Table for invalid VPIs + - I guess we can write all 1s or 0x000f in the entire memory + space or something similar. + */ + + /* This seems to work and looks right to me too !!! */ + i = REASS_TABLE * iadev->memSize; + writew((i >> 3), iadev->reass_reg+REASS_TABLE_BASE); + /* initialize Reassembly table to I don't know what ???? */ + reass_table = (u16 *)(iadev->reass_ram+i); + j = REASS_TABLE_SZ * iadev->memSize; + for(i=0; i < j; i++) + *reass_table++ = NO_AAL5_PKT; + i = 8*1024; + vcsize_sel = 0; + while (i != iadev->num_vc) { + i /= 2; + vcsize_sel++; + } + i = RX_VC_TABLE * iadev->memSize; + writew(((i>>3) & 0xfff8) | vcsize_sel, iadev->reass_reg+VC_LKUP_BASE); + vc_table = (u16 *)(iadev->reass_ram+RX_VC_TABLE*iadev->memSize); + j = RX_VC_TABLE_SZ * iadev->memSize; + for(i = 0; i < j; i++) + { + /* shift the reassembly pointer by 3 + lower 3 bits of + vc_lkup_base register (=3 for 1K VCs) and the last byte + is those low 3 bits. + Shall program this later. + */ + *vc_table = (i << 6) | 15; /* for invalid VCI */ + vc_table++; + } + /* ABR VC table */ + i = ABR_VC_TABLE * iadev->memSize; + writew(i >> 3, iadev->reass_reg+ABR_LKUP_BASE); + + i = ABR_VC_TABLE * iadev->memSize; + abr_vc_table = (struct abr_vc_table *)(iadev->reass_ram+i); + j = REASS_TABLE_SZ * iadev->memSize; + memset ((char*)abr_vc_table, 0, j * sizeof(struct abr_vc_table ) ); + for(i = 0; i < j; i++) { + abr_vc_table->rdf = 0x0003; + abr_vc_table->air = 0x5eb1; + abr_vc_table++; + } + + /* Initialize other registers */ + + /* VP Filter Register set for VC Reassembly only */ + writew(0xff00, iadev->reass_reg+VP_FILTER); + writew(0, iadev->reass_reg+XTRA_RM_OFFSET); + writew(0x1, iadev->reass_reg+PROTOCOL_ID); + + /* Packet Timeout Count related Registers : + Set packet timeout to occur in about 3 seconds + Set Packet Aging Interval count register to overflow in about 4 us + */ + writew(0xF6F8, iadev->reass_reg+PKT_TM_CNT ); + ptr16 = (u16*)j; + i = ((u32)ptr16 >> 6) & 0xff; + ptr16 += j - 1; + i |=(((u32)ptr16 << 2) & 0xff00); + writew(i, iadev->reass_reg+TMOUT_RANGE); + /* initiate the desc_tble */ + for(i=0; inum_tx_desc;i++) + iadev->desc_tbl[i].timestamp = 0; + + /* to clear the interrupt status register - read it */ + readw(iadev->reass_reg+REASS_INTR_STATUS_REG); + + /* Mask Register - clear it */ + writew(~(RX_FREEQ_EMPT|RX_PKT_RCVD), iadev->reass_reg+REASS_MASK_REG); + + skb_queue_head_init(&iadev->rx_dma_q); + iadev->rx_free_desc_qhead = NULL; + iadev->rx_open =(struct atm_vcc **)kmalloc(4*iadev->num_vc,GFP_KERNEL); + if (!iadev->rx_open) + { + printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n", + dev->number); + return -ENOMEM; + } + memset(iadev->rx_open, 0, 4*iadev->num_vc); + iadev->rxing = 1; + iadev->rx_pkt_cnt = 0; + /* Mode Register */ + writew(R_ONLINE, iadev->reass_reg+MODE_REG); + return 0; +} + + +/* + The memory map suggested in appendix A and the coding for it. + Keeping it around just in case we change our mind later. + + Buffer descr 0x0000 (128 - 4K) + UBR sched 0x1000 (1K - 4K) + UBR Wait q 0x2000 (1K - 4K) + Commn queues 0x3000 Packet Ready, Trasmit comp(0x3100) + (128 - 256) each + extended VC 0x4000 (1K - 8K) + ABR sched 0x6000 and ABR wait queue (1K - 2K) each + CBR sched 0x7000 (as needed) + VC table 0x8000 (1K - 32K) +*/ + +static void tx_intr(struct atm_dev *dev) +{ + IADEV *iadev; + unsigned short status; + unsigned long flags; + + iadev = INPH_IA_DEV(dev); + + status = readl(iadev->seg_reg+SEG_INTR_STATUS_REG); + if (status & TRANSMIT_DONE){ + + IF_EVENT(printk("Tansmit Done Intr logic run\n");) + spin_lock_irqsave(&iadev->tx_lock, flags); + ia_tx_poll(iadev); + spin_unlock_irqrestore(&iadev->tx_lock, flags); + writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); + if (iadev->close_pending) + wake_up(&iadev->close_wait); + } + if (status & TCQ_NOT_EMPTY) + { + IF_EVENT(printk("TCQ_NOT_EMPTY int received\n");) + } +} + +static void tx_dle_intr(struct atm_dev *dev) +{ + IADEV *iadev; + struct dle *dle, *cur_dle; + struct sk_buff *skb; + struct atm_vcc *vcc; + struct ia_vcc *iavcc; + u_int dle_lp; + unsigned long flags; + + iadev = INPH_IA_DEV(dev); + spin_lock_irqsave(&iadev->tx_lock, flags); + dle = iadev->tx_dle_q.read; + dle_lp = readl(iadev->dma+IPHASE5575_TX_LIST_ADDR) & + (sizeof(struct dle)*DLE_ENTRIES - 1); + cur_dle = (struct dle*)(iadev->tx_dle_q.start + (dle_lp >> 4)); + while (dle != cur_dle) + { + /* free the DMAed skb */ + skb = skb_dequeue(&iadev->tx_dma_q); + if (!skb) break; + vcc = ATM_SKB(skb)->vcc; + if (!vcc) { + printk("tx_dle_intr: vcc is null\n"); + dev_kfree_skb(skb); + return; + } + iavcc = INPH_IA_VCC(vcc); + if (!iavcc) { + printk("tx_dle_intr: iavcc is null\n"); + dev_kfree_skb(skb); + return; + } + if (vcc->qos.txtp.pcr >= iadev->rate_limit) { + if ((vcc->pop) && (skb->len != 0)) + { + vcc->pop(vcc, skb); + } + else { + dev_kfree_skb(skb); + } + } + else { /* Hold the rate-limited skb for flow control */ + IA_SKB_STATE(skb) |= IA_DLED; + skb_queue_tail(&iavcc->txing_skb, skb); + } + IF_EVENT(printk("tx_dle_intr: enque skb = 0x%x \n", (u32)skb);) + if (++dle == iadev->tx_dle_q.end) + dle = iadev->tx_dle_q.start; + } + iadev->tx_dle_q.read = dle; + spin_unlock_irqrestore(&iadev->tx_lock, flags); +} + +static int open_tx(struct atm_vcc *vcc) +{ + struct ia_vcc *ia_vcc; + IADEV *iadev; + struct main_vc *vc; + struct ext_vc *evc; + int ret; + IF_EVENT(printk("iadev: open_tx entered vcc->vci = %d\n", vcc->vci);) + if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; + iadev = INPH_IA_DEV(vcc->dev); + + if (iadev->phy_type & FE_25MBIT_PHY) { + if (vcc->qos.txtp.traffic_class == ATM_ABR) { + printk("IA: ABR not support\n"); + return -EINVAL; + } + if (vcc->qos.txtp.traffic_class == ATM_CBR) { + printk("IA: CBR not support\n"); + return -EINVAL; + } + } + ia_vcc = INPH_IA_VCC(vcc); + memset((caddr_t)ia_vcc, 0, sizeof(struct ia_vcc)); + if (vcc->qos.txtp.max_sdu > + (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){ + printk("IA: SDU size over the configured SDU size %d\n", + iadev->tx_buf_sz); + kfree(ia_vcc); + return -EINVAL; + } + ia_vcc->vc_desc_cnt = 0; + ia_vcc->txing = 1; + + /* find pcr */ + if (vcc->qos.txtp.max_pcr == ATM_MAX_PCR) + vcc->qos.txtp.pcr = iadev->LineRate; + else if ((vcc->qos.txtp.max_pcr == 0)&&( vcc->qos.txtp.pcr <= 0)) + vcc->qos.txtp.pcr = iadev->LineRate; + else if ((vcc->qos.txtp.max_pcr > vcc->qos.txtp.pcr) && (vcc->qos.txtp.max_pcr> 0)) + vcc->qos.txtp.pcr = vcc->qos.txtp.max_pcr; + if (vcc->qos.txtp.pcr > iadev->LineRate) + vcc->qos.txtp.pcr = iadev->LineRate; + ia_vcc->pcr = vcc->qos.txtp.pcr; + + if (ia_vcc->pcr > (iadev->LineRate / 6) ) ia_vcc->ltimeout = HZ / 10; + else if (ia_vcc->pcr > (iadev->LineRate / 130)) ia_vcc->ltimeout = HZ; + else if (ia_vcc->pcr <= 170) ia_vcc->ltimeout = 16 * HZ; + else ia_vcc->ltimeout = 2700 * HZ / ia_vcc->pcr; + if (ia_vcc->pcr < iadev->rate_limit) + skb_queue_head_init (&ia_vcc->txing_skb); + if (ia_vcc->pcr < iadev->rate_limit) { + if (vcc->qos.txtp.max_sdu != 0) { + if (ia_vcc->pcr > 60000) + vcc->sk->sndbuf = vcc->qos.txtp.max_sdu * 5; + else if (ia_vcc->pcr > 2000) + vcc->sk->sndbuf = vcc->qos.txtp.max_sdu * 4; + else + vcc->sk->sndbuf = 3*vcc->qos.txtp.max_sdu; + } + else + vcc->sk->sndbuf = 24576; + } + + vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR; + evc = (struct ext_vc *)iadev->EXT_VC_TABLE_ADDR; + vc += vcc->vci; + evc += vcc->vci; + memset((caddr_t)vc, 0, sizeof(struct main_vc)); + memset((caddr_t)evc, 0, sizeof(struct ext_vc)); + + /* store the most significant 4 bits of vci as the last 4 bits + of first part of atm header. + store the last 12 bits of vci as first 12 bits of the second + part of the atm header. + */ + evc->atm_hdr1 = (vcc->vci >> 12) & 0x000f; + evc->atm_hdr2 = (vcc->vci & 0x0fff) << 4; + + /* check the following for different traffic classes */ + if (vcc->qos.txtp.traffic_class == ATM_UBR) + { + vc->type = UBR; + vc->status = CRC_APPEND; + vc->acr = cellrate_to_float(iadev->LineRate); + if (vcc->qos.txtp.pcr > 0) + vc->acr = cellrate_to_float(vcc->qos.txtp.pcr); + IF_UBR(printk("UBR: txtp.pcr = 0x%d f_rate = 0x%x\n", + vcc->qos.txtp.max_pcr,vc->acr);) + } + else if (vcc->qos.txtp.traffic_class == ATM_ABR) + { srv_cls_param_t srv_p; + IF_ABR(printk("Tx ABR VCC\n");) + init_abr_vc(iadev, &srv_p); + if (vcc->qos.txtp.pcr > 0) + srv_p.pcr = vcc->qos.txtp.pcr; + if (vcc->qos.txtp.min_pcr > 0) { + int tmpsum = iadev->sum_mcr+iadev->sum_cbr+vcc->qos.txtp.min_pcr; + if (tmpsum > iadev->LineRate) + return -EBUSY; + srv_p.mcr = vcc->qos.txtp.min_pcr; + iadev->sum_mcr += vcc->qos.txtp.min_pcr; + } + else srv_p.mcr = 0; + if (vcc->qos.txtp.icr) + srv_p.icr = vcc->qos.txtp.icr; + if (vcc->qos.txtp.tbe) + srv_p.tbe = vcc->qos.txtp.tbe; + if (vcc->qos.txtp.frtt) + srv_p.frtt = vcc->qos.txtp.frtt; + if (vcc->qos.txtp.rif) + srv_p.rif = vcc->qos.txtp.rif; + if (vcc->qos.txtp.rdf) + srv_p.rdf = vcc->qos.txtp.rdf; + if (vcc->qos.txtp.nrm_pres) + srv_p.nrm = vcc->qos.txtp.nrm; + if (vcc->qos.txtp.trm_pres) + srv_p.trm = vcc->qos.txtp.trm; + if (vcc->qos.txtp.adtf_pres) + srv_p.adtf = vcc->qos.txtp.adtf; + if (vcc->qos.txtp.cdf_pres) + srv_p.cdf = vcc->qos.txtp.cdf; + if (srv_p.icr > srv_p.pcr) + srv_p.icr = srv_p.pcr; + IF_ABR(printk("ABR:vcc->qos.txtp.max_pcr = %d mcr = %d\n", + srv_p.pcr, srv_p.mcr);) + ia_open_abr_vc(iadev, &srv_p, vcc, 1); + } else if (vcc->qos.txtp.traffic_class == ATM_CBR) { + if (iadev->phy_type & FE_25MBIT_PHY) { + printk("IA: CBR not support\n"); + return -EINVAL; + } + if (vcc->qos.txtp.max_pcr > iadev->LineRate) { + IF_CBR(printk("PCR is not availble\n");) + return -1; + } + vc->type = CBR; + vc->status = CRC_APPEND; + if ((ret = ia_cbr_setup (iadev, vcc)) < 0) { + return ret; + } + } + else + printk("iadev: Non UBR, ABR and CBR traffic not supportedn"); + + iadev->testTable[vcc->vci]->vc_status |= VC_ACTIVE; + IF_EVENT(printk("ia open_tx returning \n");) + return 0; +} + + +static int tx_init(struct atm_dev *dev) +{ + IADEV *iadev; + struct tx_buf_desc *buf_desc_ptr; + unsigned int tx_pkt_start; + u32 *dle_addr; + int i; + u_short tcq_st_adr; + u_short *tcq_start; + u_short prq_st_adr; + u_short *prq_start; + struct main_vc *vc; + struct ext_vc *evc; + u_short tmp16; + u32 vcsize_sel; + + iadev = INPH_IA_DEV(dev); + spin_lock_init(&iadev->tx_lock); + + IF_INIT(printk("Tx MASK REG: 0x%0x\n", + readw(iadev->seg_reg+SEG_MASK_REG));) + /*---------- Initializing Transmit DLEs ----------*/ + /* allocating 8k memory for transmit DLEs */ + dle_addr = (u32*)kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL); + if (!dle_addr) + { + printk(KERN_ERR DEV_LABEL "can't allocate TX DLEs\n"); + } + + /* find 4k byte boundary within the 8k allocated */ + dle_addr = (u32*)(((u32)dle_addr+(4096-1)) & ~(4096-1)); + iadev->tx_dle_q.start = (struct dle*)dle_addr; + iadev->tx_dle_q.read = iadev->tx_dle_q.start; + iadev->tx_dle_q.write = iadev->tx_dle_q.start; + iadev->tx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES); + + /* write the upper 20 bits of the start address to tx list address register */ + writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_TX_LIST_ADDR); + writew(0xffff, iadev->seg_reg+SEG_MASK_REG); + writew(0, iadev->seg_reg+MODE_REG_0); + writew(RESET_SEG, iadev->seg_reg+SEG_COMMAND_REG); + iadev->MAIN_VC_TABLE_ADDR = iadev->seg_ram+MAIN_VC_TABLE*iadev->memSize; + iadev->EXT_VC_TABLE_ADDR = iadev->seg_ram+EXT_VC_TABLE*iadev->memSize; + iadev->ABR_SCHED_TABLE_ADDR=iadev->seg_ram+ABR_SCHED_TABLE*iadev->memSize; + + /* + Transmit side control memory map + -------------------------------- + Buffer descr 0x0000 (128 - 4K) + Commn queues 0x1000 Transmit comp, Packet ready(0x1400) + (512 - 1K) each + TCQ - 4K, PRQ - 5K + CBR Table 0x1800 (as needed) - 6K + UBR Table 0x3000 (1K - 4K) - 12K + UBR Wait queue 0x4000 (1K - 4K) - 16K + ABR sched 0x5000 and ABR wait queue (1K - 2K) each + ABR Tbl - 20K, ABR Wq - 22K + extended VC 0x6000 (1K - 8K) - 24K + VC Table 0x8000 (1K - 32K) - 32K + + Between 0x2000 (8K) and 0x3000 (12K) there is 4K space left for VBR Tbl + and Wait q, which can be allotted later. + */ + + /* Buffer Descriptor Table Base address */ + writew(TX_DESC_BASE, iadev->seg_reg+SEG_DESC_BASE); + + /* initialize each entry in the buffer descriptor table */ + buf_desc_ptr =(struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE); + memset((caddr_t)buf_desc_ptr, 0, sizeof(struct tx_buf_desc)); + buf_desc_ptr++; + tx_pkt_start = TX_PACKET_RAM; + for(i=1; i<=iadev->num_tx_desc; i++) + { + memset((caddr_t)buf_desc_ptr, 0, sizeof(struct tx_buf_desc)); + buf_desc_ptr->desc_mode = AAL5; + buf_desc_ptr->buf_start_hi = tx_pkt_start >> 16; + buf_desc_ptr->buf_start_lo = tx_pkt_start & 0x0000ffff; + buf_desc_ptr++; + tx_pkt_start += iadev->tx_buf_sz; + } + iadev->tx_buf= (caddr_t*)kmalloc(iadev->num_tx_desc*sizeof(caddr_t), + GFP_KERNEL); + if (!iadev->tx_buf) { + printk(KERN_ERR DEV_LABEL " couldn't get mem\n"); + return -EAGAIN; + } + for (i= 0; i< iadev->num_tx_desc; i++) + { + + iadev->tx_buf[i] =(caddr_t)kmalloc(sizeof(struct cpcs_trailer), + GFP_KERNEL|GFP_DMA); + if(!iadev->tx_buf[i]) { + printk(KERN_ERR DEV_LABEL " couldn't get freepage\n"); + return -EAGAIN; + } + } + iadev->desc_tbl = (struct desc_tbl_t *)kmalloc(iadev->num_tx_desc * + sizeof(struct desc_tbl_t), GFP_KERNEL); + + /* Communication Queues base address */ + i = TX_COMP_Q * iadev->memSize; + writew(i >> 16, iadev->seg_reg+SEG_QUEUE_BASE); + + /* Transmit Complete Queue */ + writew(i, iadev->seg_reg+TCQ_ST_ADR); + writew(i, iadev->seg_reg+TCQ_RD_PTR); + writew(i+iadev->num_tx_desc*sizeof(u_short),iadev->seg_reg+TCQ_WR_PTR); + iadev->host_tcq_wr = i + iadev->num_tx_desc*sizeof(u_short); + writew(i+2 * iadev->num_tx_desc * sizeof(u_short), + iadev->seg_reg+TCQ_ED_ADR); + /* Fill the TCQ with all the free descriptors. */ + tcq_st_adr = readw(iadev->seg_reg+TCQ_ST_ADR); + tcq_start = (u_short *)(iadev->seg_ram+tcq_st_adr); + for(i=1; i<=iadev->num_tx_desc; i++) + { + *tcq_start = (u_short)i; + tcq_start++; + } + + /* Packet Ready Queue */ + i = PKT_RDY_Q * iadev->memSize; + writew(i, iadev->seg_reg+PRQ_ST_ADR); + writew(i+2 * iadev->num_tx_desc * sizeof(u_short), + iadev->seg_reg+PRQ_ED_ADR); + writew(i, iadev->seg_reg+PRQ_RD_PTR); + writew(i, iadev->seg_reg+PRQ_WR_PTR); + + /* Load local copy of PRQ and TCQ ptrs */ + iadev->ffL.prq_st = readw(iadev->seg_reg+PRQ_ST_ADR) & 0xffff; + iadev->ffL.prq_ed = readw(iadev->seg_reg+PRQ_ED_ADR) & 0xffff; + iadev->ffL.prq_wr = readw(iadev->seg_reg+PRQ_WR_PTR) & 0xffff; + + iadev->ffL.tcq_st = readw(iadev->seg_reg+TCQ_ST_ADR) & 0xffff; + iadev->ffL.tcq_ed = readw(iadev->seg_reg+TCQ_ED_ADR) & 0xffff; + iadev->ffL.tcq_rd = readw(iadev->seg_reg+TCQ_RD_PTR) & 0xffff; + + /* Just for safety initializing the queue to have desc 1 always */ + /* Fill the PRQ with all the free descriptors. */ + prq_st_adr = readw(iadev->seg_reg+PRQ_ST_ADR); + prq_start = (u_short *)(iadev->seg_ram+prq_st_adr); + for(i=1; i<=iadev->num_tx_desc; i++) + { + *prq_start = (u_short)0; /* desc 1 in all entries */ + prq_start++; + } + /* CBR Table */ + IF_INIT(printk("Start CBR Init\n");) +#if 1 /* for 1K VC board, CBR_PTR_BASE is 0 */ + writew(0,iadev->seg_reg+CBR_PTR_BASE); +#else /* Charlie's logic is wrong ? */ + tmp16 = (iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize)>>17; + IF_INIT(printk("cbr_ptr_base = 0x%x ", tmp16);) + writew(tmp16,iadev->seg_reg+CBR_PTR_BASE); +#endif + + IF_INIT(printk("value in register = 0x%x\n", + readw(iadev->seg_reg+CBR_PTR_BASE));) + tmp16 = (CBR_SCHED_TABLE*iadev->memSize) >> 1; + writew(tmp16, iadev->seg_reg+CBR_TAB_BEG); + IF_INIT(printk("cbr_tab_beg = 0x%x in reg = 0x%x \n", tmp16, + readw(iadev->seg_reg+CBR_TAB_BEG));) + writew(tmp16, iadev->seg_reg+CBR_TAB_END+1); // CBR_PTR; + tmp16 = (CBR_SCHED_TABLE*iadev->memSize + iadev->num_vc*6 - 2) >> 1; + writew(tmp16, iadev->seg_reg+CBR_TAB_END); + IF_INIT(printk("iadev->seg_reg = 0x%x CBR_PTR_BASE = 0x%x\n", + (u32)iadev->seg_reg, readw(iadev->seg_reg+CBR_PTR_BASE));) + IF_INIT(printk("CBR_TAB_BEG = 0x%x, CBR_TAB_END = 0x%x, CBR_PTR = 0x%x\n", + readw(iadev->seg_reg+CBR_TAB_BEG), readw(iadev->seg_reg+CBR_TAB_END), + readw(iadev->seg_reg+CBR_TAB_END+1));) + tmp16 = (iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize); + + /* Initialize the CBR Schedualing Table */ + memset((caddr_t)(iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize), + 0, iadev->num_vc*6); + iadev->CbrRemEntries = iadev->CbrTotEntries = iadev->num_vc*3; + iadev->CbrEntryPt = 0; + iadev->Granularity = MAX_ATM_155 / iadev->CbrTotEntries; + iadev->NumEnabledCBR = 0; + + /* UBR scheduling Table and wait queue */ + /* initialize all bytes of UBR scheduler table and wait queue to 0 + - SCHEDSZ is 1K (# of entries). + - UBR Table size is 4K + - UBR wait queue is 4K + since the table and wait queues are contiguous, all the bytes + can be intialized by one memeset. + */ + + vcsize_sel = 0; + i = 8*1024; + while (i != iadev->num_vc) { + i /= 2; + vcsize_sel++; + } + + i = MAIN_VC_TABLE * iadev->memSize; + writew(vcsize_sel | ((i >> 8) & 0xfff8),iadev->seg_reg+VCT_BASE); + i = EXT_VC_TABLE * iadev->memSize; + writew((i >> 8) & 0xfffe, iadev->seg_reg+VCTE_BASE); + i = UBR_SCHED_TABLE * iadev->memSize; + writew((i & 0xffff) >> 11, iadev->seg_reg+UBR_SBPTR_BASE); + i = UBR_WAIT_Q * iadev->memSize; + writew((i >> 7) & 0xffff, iadev->seg_reg+UBRWQ_BASE); + memset((caddr_t)(iadev->seg_ram+UBR_SCHED_TABLE*iadev->memSize), + 0, iadev->num_vc*8); + /* ABR scheduling Table(0x5000-0x57ff) and wait queue(0x5800-0x5fff)*/ + /* initialize all bytes of ABR scheduler table and wait queue to 0 + - SCHEDSZ is 1K (# of entries). + - ABR Table size is 2K + - ABR wait queue is 2K + since the table and wait queues are contiguous, all the bytes + can be intialized by one memeset. + */ + i = ABR_SCHED_TABLE * iadev->memSize; + writew((i >> 11) & 0xffff, iadev->seg_reg+ABR_SBPTR_BASE); + i = ABR_WAIT_Q * iadev->memSize; + writew((i >> 7) & 0xffff, iadev->seg_reg+ABRWQ_BASE); + + i = ABR_SCHED_TABLE*iadev->memSize; + memset((caddr_t)(iadev->seg_ram+i), 0, iadev->num_vc*4); + vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR; + evc = (struct ext_vc *)iadev->EXT_VC_TABLE_ADDR; + iadev->testTable = (struct testTable_t **) + kmalloc(sizeof(long)*iadev->num_vc, GFP_KERNEL); + if (!iadev->testTable) { + printk("Get freepage failed\n"); + return -EAGAIN; + } + for(i=0; inum_vc; i++) + { + memset((caddr_t)vc, 0, sizeof(struct main_vc)); + memset((caddr_t)evc, 0, sizeof(struct ext_vc)); + iadev->testTable[i] = (struct testTable_t *) + kmalloc(sizeof(struct testTable_t), GFP_KERNEL); + iadev->testTable[i]->lastTime = 0; + iadev->testTable[i]->fract = 0; + iadev->testTable[i]->vc_status = VC_UBR; + vc++; + evc++; + } + + /* Other Initialization */ + + /* Max Rate Register */ + if (iadev->phy_type & FE_25MBIT_PHY) { + writew(RATE25, iadev->seg_reg+MAXRATE); + writew((UBR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); + } + else { + writew(cellrate_to_float(iadev->LineRate),iadev->seg_reg+MAXRATE); + writew((UBR_EN | ABR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); + } + /* Set Idle Header Reigisters to be sure */ + writew(0, iadev->seg_reg+IDLEHEADHI); + writew(0, iadev->seg_reg+IDLEHEADLO); + + /* Program ABR UBR Priority Register as PRI_ABR_UBR_EQUAL */ + writew(0xaa00, iadev->seg_reg+ABRUBR_ARB); + + iadev->close_pending = 0; +#if LINUX_VERSION_CODE >= 0x20303 + init_waitqueue_head(&iadev->close_wait); + init_waitqueue_head(&iadev->timeout_wait); +#else + iadev->close_wait = NULL; + iadev->timeout_wait = NULL; +#endif + skb_queue_head_init(&iadev->tx_dma_q); + ia_init_rtn_q(&iadev->tx_return_q); + + /* RM Cell Protocol ID and Message Type */ + writew(RM_TYPE_4_0, iadev->seg_reg+RM_TYPE); + skb_queue_head_init (&iadev->tx_backlog); + + /* Mode Register 1 */ + writew(MODE_REG_1_VAL, iadev->seg_reg+MODE_REG_1); + + /* Mode Register 0 */ + writew(T_ONLINE, iadev->seg_reg+MODE_REG_0); + + /* Interrupt Status Register - read to clear */ + readw(iadev->seg_reg+SEG_INTR_STATUS_REG); + + /* Interrupt Mask Reg- don't mask TCQ_NOT_EMPTY interrupt generation */ + writew(~(TRANSMIT_DONE | TCQ_NOT_EMPTY), iadev->seg_reg+SEG_MASK_REG); + writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); + iadev->tx_pkt_cnt = 0; + iadev->rate_limit = iadev->LineRate / 3; + + return 0; +} + +static void ia_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct atm_dev *dev; + IADEV *iadev; + unsigned int status; + + dev = dev_id; + iadev = INPH_IA_DEV(dev); + while( (status = readl(iadev->reg+IPHASE5575_BUS_STATUS_REG) & 0x7f)) + { + IF_EVENT(printk("ia_int: status = 0x%x\n", status);) + if (status & STAT_REASSINT) + { + /* do something */ + IF_EVENT(printk("REASSINT Bus status reg: %08x\n", status);) + rx_intr(dev); + } + if (status & STAT_DLERINT) + { + /* Clear this bit by writing a 1 to it. */ + *(u_int *)(iadev->reg+IPHASE5575_BUS_STATUS_REG) = STAT_DLERINT; + rx_dle_intr(dev); + } + if (status & STAT_SEGINT) + { + /* do something */ + IF_EVENT(printk("IA: tx_intr \n");) + tx_intr(dev); + } + if (status & STAT_DLETINT) + { + *(u_int *)(iadev->reg+IPHASE5575_BUS_STATUS_REG) = STAT_DLETINT; + tx_dle_intr(dev); + } + if (status & (STAT_FEINT | STAT_ERRINT | STAT_MARKINT)) + { + if (status & STAT_FEINT) + IaFrontEndIntr(iadev); + } + } +} + + + +/*----------------------------- entries --------------------------------*/ +static int get_esi(struct atm_dev *dev) +{ + IADEV *iadev; + int i; + u32 mac1; + u16 mac2; + + iadev = INPH_IA_DEV(dev); + mac1 = cpu_to_be32(le32_to_cpu(readl( + iadev->reg+IPHASE5575_MAC1))); + mac2 = cpu_to_be16(le16_to_cpu(readl(iadev->reg+IPHASE5575_MAC2))); + IF_INIT(printk("ESI: 0x%08x%04x\n", mac1, mac2);) + for (i=0; iesi[i] = mac1 >>(8*(MAC1_LEN-1-i)); + + for (i=0; iesi[i+MAC1_LEN] = mac2 >>(8*(MAC2_LEN - 1 -i)); + return 0; +} + +static int reset_sar(struct atm_dev *dev) +{ + IADEV *iadev; + int i, error = 1; + unsigned int pci[64]; + + iadev = INPH_IA_DEV(dev); + for(i=0; i<64; i++) + if ((error = pci_read_config_dword(iadev->pci, + i*4, &pci[i])) != PCIBIOS_SUCCESSFUL) + return error; + writel(0, iadev->reg+IPHASE5575_EXT_RESET); + for(i=0; i<64; i++) + if ((error = pci_write_config_dword(iadev->pci, + i*4, pci[i])) != PCIBIOS_SUCCESSFUL) + return error; + udelay(5); + return 0; +} + + +#if LINUX_VERSION_CODE >= 0x20312 +static int __init ia_init(struct atm_dev *dev) +#else +__initfunc(static int ia_init(struct atm_dev *dev)) +#endif +{ + IADEV *iadev; + unsigned int real_base, base; + unsigned short command; + unsigned char revision; + int error, i; + + /* The device has been identified and registered. Now we read + necessary configuration info like memory base address, + interrupt number etc */ + + IF_INIT(printk(">ia_init\n");) + dev->ci_range.vpi_bits = 0; + dev->ci_range.vci_bits = NR_VCI_LD; + + iadev = INPH_IA_DEV(dev); + + if ((error = pci_read_config_word(iadev->pci, PCI_COMMAND,&command)) + || (error = pci_read_config_dword(iadev->pci, + PCI_BASE_ADDRESS_0,&real_base)) + || (error = pci_read_config_byte(iadev->pci, + PCI_INTERRUPT_LINE,&iadev->irq)) + || (error = pci_read_config_byte(iadev->pci, + PCI_REVISION_ID,&revision))) + { + printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%x\n", + dev->number,error); + return -EINVAL; + } + IF_INIT(printk(DEV_LABEL "(itf %d): rev.%d,realbase=0x%x,irq=%d\n", + dev->number, revision, real_base, iadev->irq);) + + /* find mapping size of board */ + + /* write all 1's into the base address register. + read the register whic returns us 0's in the don't care bits. + size is calculated as ~(don't cre bits) + 1 */ + + if (pci_write_config_dword(iadev->pci, + PCI_BASE_ADDRESS_0, 0xffffffff)!=PCIBIOS_SUCCESSFUL) + { + printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, + error); + return -EINVAL; + } + if(pci_read_config_dword(iadev->pci, PCI_BASE_ADDRESS_0, + &(iadev->pci_map_size)) !=PCIBIOS_SUCCESSFUL) + { + printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, + error); + return -EINVAL; + } + iadev->pci_map_size &= PCI_BASE_ADDRESS_MEM_MASK; + iadev->pci_map_size = ~iadev->pci_map_size + 1; + if (iadev->pci_map_size == 0x100000){ + iadev->num_vc = 4096; + dev->ci_range.vci_bits = NR_VCI_4K_LD; + iadev->memSize = 4; + } + else if (iadev->pci_map_size == 0x40000) { + iadev->num_vc = 1024; + iadev->memSize = 1; + } + else { + printk("Unknown pci_map_size = 0x%x\n", iadev->pci_map_size); + return -EINVAL; + } + IF_INIT(printk (DEV_LABEL "map size: %i\n", iadev->pci_map_size);) + if(pci_write_config_dword(iadev->pci, PCI_BASE_ADDRESS_0, + real_base)!=PCIBIOS_SUCCESSFUL) + { + printk(DEV_LABEL "(itf %d): init error 0x%x\n",dev->number, + error); + return -EINVAL; + } + + /* strip flags (last 4 bits ) ---> mask with 0xfffffff0 */ + real_base &= MEM_VALID; + /* enabling the responses in memory space */ + command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if ((error = pci_write_config_word(iadev->pci, + PCI_COMMAND, command))) + { + printk(DEV_LABEL "(itf %d): can't enable memory (0x%x)\n", + dev->number,error); + return error; + } + /* + * Delay at least 1us before doing any mem accesses (how 'bout 10?) + */ + udelay(10); + + /* mapping the physical address to a virtual address in address space */ + base=(unsigned long)ioremap((unsigned long)real_base,iadev->pci_map_size); /* ioremap is not resolved ??? */ + + if (!base) + { + printk(DEV_LABEL " (itf %d): can't set up page mapping\n", + dev->number); + return error; + } + IF_INIT(printk(DEV_LABEL " (itf %d): rev.%d,base=0x%x,irq=%d\n", + dev->number, revision, base, iadev->irq);) + + /* filling the iphase dev structure */ + iadev->mem = iadev->pci_map_size /2; + iadev->base_diff = real_base - base; + iadev->real_base = real_base; + iadev->base = base; + + /* Bus Interface Control Registers */ + iadev->reg = (u32 *) (base + REG_BASE); + /* Segmentation Control Registers */ + iadev->seg_reg = (u32 *) (base + SEG_BASE); + /* Reassembly Control Registers */ + iadev->reass_reg = (u32 *) (base + REASS_BASE); + /* Front end/ DMA control registers */ + iadev->phy = (u32 *) (base + PHY_BASE); + iadev->dma = (u32 *) (base + PHY_BASE); + /* RAM - Segmentation RAm and Reassembly RAM */ + iadev->ram = (u32 *) (base + ACTUAL_RAM_BASE); + iadev->seg_ram = (base + ACTUAL_SEG_RAM_BASE); + iadev->reass_ram = (base + ACTUAL_REASS_RAM_BASE); + + /* lets print out the above */ + IF_INIT(printk("Base addrs: %08x %08x %08x \n %08x %08x %08x %08x\n", + (u32)iadev->reg,(u32)iadev->seg_reg,(u32)iadev->reass_reg, + (u32)iadev->phy, (u32)iadev->ram, (u32)iadev->seg_ram, + (u32)iadev->reass_ram);) + + /* lets try reading the MAC address */ + error = get_esi(dev); + if (error) return error; + printk("IA: "); + for (i=0; i < ESI_LEN; i++) + printk("%s%02X",i ? "-" : "",dev->esi[i]); + printk("\n"); + + /* reset SAR */ + if (reset_sar(dev)) { + printk("IA: reset SAR fail, please try again\n"); + return 1; + } + return 0; +} + +static void ia_update_stats(IADEV *iadev) { + if (!iadev->carrier_detect) + return; + iadev->rx_cell_cnt += readw(iadev->reass_reg+CELL_CTR0)&0xffff; + iadev->rx_cell_cnt += (readw(iadev->reass_reg+CELL_CTR1) & 0xffff) << 16; + iadev->drop_rxpkt += readw(iadev->reass_reg + DRP_PKT_CNTR ) & 0xffff; + iadev->drop_rxcell += readw(iadev->reass_reg + ERR_CNTR) & 0xffff; + iadev->tx_cell_cnt += readw(iadev->seg_reg + CELL_CTR_LO_AUTO)&0xffff; + iadev->tx_cell_cnt += (readw(iadev->seg_reg+CELL_CTR_HIGH_AUTO)&0xffff)<<16; + return; +} + +static void ia_led_timer(unsigned long arg) { + unsigned long flags; + static u_char blinking[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + u_char i; + static u32 ctrl_reg; + for (i = 0; i < iadev_count; i++) { + if (ia_dev[i]) { + ctrl_reg = readl(ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); + if (blinking[i] == 0) { + blinking[i]++; + ctrl_reg &= (~CTRL_LED); + writel(ctrl_reg, ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); + ia_update_stats(ia_dev[i]); + } + else { + blinking[i] = 0; + ctrl_reg |= CTRL_LED; + writel(ctrl_reg, ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); + spin_lock_irqsave(&ia_dev[i]->tx_lock, flags); + if (ia_dev[i]->close_pending) + wake_up(&ia_dev[i]->close_wait); + ia_tx_poll(ia_dev[i]); + spin_unlock_irqrestore(&ia_dev[i]->tx_lock, flags); + } + } + } + mod_timer(&ia_timer, jiffies + HZ / 4); + return; +} + +static void ia_phy_put(struct atm_dev *dev, unsigned char value, + unsigned long addr) +{ + writel(value, INPH_IA_DEV(dev)->phy+addr); +} + +static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr) +{ + return readl(INPH_IA_DEV(dev)->phy+addr); +} + +#if LINUX_VERSION_CODE >= 0x20312 +static int __init ia_start(struct atm_dev *dev) +#else +__initfunc(static int ia_start(struct atm_dev *dev)) +#endif +{ + IADEV *iadev; + int error = 1; + unsigned char phy; + u32 ctrl_reg; + IF_EVENT(printk(">ia_start\n");) + iadev = INPH_IA_DEV(dev); + if (request_irq(iadev->irq, &ia_int, SA_SHIRQ, DEV_LABEL, dev)) { + printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", + dev->number, iadev->irq); + return -EAGAIN; + } + /* @@@ should release IRQ on error */ + /* enabling memory + master */ + if ((error = pci_write_config_word(iadev->pci, + PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ))) + { + printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" + "master (0x%x)\n",dev->number, error); + free_irq(iadev->irq, dev); + return error; + } + udelay(10); + + /* Maybe we should reset the front end, initialize Bus Interface Control + Registers and see. */ + + IF_INIT(printk("Bus ctrl reg: %08x\n", + readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG));) + ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG); + ctrl_reg = (ctrl_reg & (CTRL_LED | CTRL_FE_RST)) + | CTRL_B8 + | CTRL_B16 + | CTRL_B32 + | CTRL_B48 + | CTRL_B64 + | CTRL_B128 + | CTRL_ERRMASK + | CTRL_DLETMASK /* shud be removed l8r */ + | CTRL_DLERMASK + | CTRL_SEGMASK + | CTRL_REASSMASK + | CTRL_FEMASK + | CTRL_CSPREEMPT; + + writel(ctrl_reg, iadev->reg+IPHASE5575_BUS_CONTROL_REG); + + IF_INIT(printk("Bus ctrl reg after initializing: %08x\n", + readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG)); + printk("Bus status reg after init: %08x\n", + readl(iadev->reg+IPHASE5575_BUS_STATUS_REG));) + + ia_hw_type(iadev); + error = tx_init(dev); + if (error) { + free_irq(iadev->irq, dev); + return error; + } + error = rx_init(dev); + if (error) { + free_irq(iadev->irq, dev); + return error; + } + + ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG); + writel(ctrl_reg | CTRL_FE_RST, iadev->reg+IPHASE5575_BUS_CONTROL_REG); + IF_INIT(printk("Bus ctrl reg after initializing: %08x\n", + readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG));) + phy = 0; /* resolve compiler complaint */ + IF_INIT ( + if ((phy=ia_phy_get(dev,0)) == 0x30) + printk("IA: pm5346,rev.%d\n",phy&0x0f); + else + printk("IA: utopia,rev.%0x\n",phy);) + + if (iadev->phy_type & FE_25MBIT_PHY) { + ia_mb25_init(iadev); + return 0; + } + if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) { + ia_suni_pm7345_init(iadev); + return 0; + } + + error = suni_init(dev); + if (error) { + free_irq(iadev->irq, dev); + return error; + } + + /* Enable interrupt on loss of signal SUNI_RSOP_CIE 0x10 + SUNI_RSOP_CIE_LOSE - 0x04 + */ + ia_phy_put(dev, ia_phy_get(dev,0x10) | 0x04, 0x10); +#ifndef MODULE + error = dev->phy->start(dev); + if (error) { + free_irq(iadev->irq, dev); + return error; + } +#endif + /* Get iadev->carrier_detect status */ + IaFrontEndIntr(iadev); + return 0; +} + +static void ia_close(struct atm_vcc *vcc) +{ + u16 *vc_table; + IADEV *iadev; + struct ia_vcc *ia_vcc; + struct sk_buff *skb = NULL; + struct sk_buff_head tmp_tx_backlog, tmp_vcc_backlog; + unsigned long closetime, flags; + int ctimeout; + + iadev = INPH_IA_DEV(vcc->dev); + ia_vcc = INPH_IA_VCC(vcc); + if (!ia_vcc) return; + + IF_EVENT(printk("ia_close: ia_vcc->vc_desc_cnt = %d vci = %d\n", + ia_vcc->vc_desc_cnt,vcc->vci);) + vcc->flags &= ~ATM_VF_READY; + skb_queue_head_init (&tmp_tx_backlog); + skb_queue_head_init (&tmp_vcc_backlog); + if (vcc->qos.txtp.traffic_class != ATM_NONE) { + iadev->close_pending++; + sleep_on_timeout(&iadev->timeout_wait, 50); + spin_lock_irqsave(&iadev->tx_lock, flags); + while((skb = skb_dequeue(&iadev->tx_backlog))) { + if (ATM_SKB(skb)->vcc == vcc){ + if (vcc->pop) vcc->pop(vcc, skb); + else dev_kfree_skb(skb); + } + else + skb_queue_tail(&tmp_tx_backlog, skb); + } + while((skb = skb_dequeue(&tmp_tx_backlog))) + skb_queue_tail(&iadev->tx_backlog, skb); + IF_EVENT(printk("IA TX Done decs_cnt = %d\n", ia_vcc->vc_desc_cnt);) + closetime = jiffies; + ctimeout = 300000 / ia_vcc->pcr; + if (ctimeout == 0) + ctimeout = 1; + while (ia_vcc->vc_desc_cnt > 0){ + if ((jiffies - closetime) >= ctimeout) + break; + spin_unlock_irqrestore(&iadev->tx_lock, flags); + sleep_on(&iadev->close_wait); + spin_lock_irqsave(&iadev->tx_lock, flags); + } + iadev->close_pending--; + iadev->testTable[vcc->vci]->lastTime = 0; + iadev->testTable[vcc->vci]->fract = 0; + iadev->testTable[vcc->vci]->vc_status = VC_UBR; + if (vcc->qos.txtp.traffic_class == ATM_ABR) { + if (vcc->qos.txtp.min_pcr > 0) + iadev->sum_mcr -= vcc->qos.txtp.min_pcr; + } + if (vcc->qos.txtp.traffic_class == ATM_CBR) { + ia_vcc = INPH_IA_VCC(vcc); + iadev->sum_mcr -= ia_vcc->NumCbrEntry*iadev->Granularity; + ia_cbrVc_close (vcc); + } + spin_unlock_irqrestore(&iadev->tx_lock, flags); + } + + if (vcc->qos.rxtp.traffic_class != ATM_NONE) { + // reset reass table + vc_table = (u16 *)(iadev->reass_ram+REASS_TABLE*iadev->memSize); + vc_table += vcc->vci; + *vc_table = NO_AAL5_PKT; + // reset vc table + vc_table = (u16 *)(iadev->reass_ram+RX_VC_TABLE*iadev->memSize); + vc_table += vcc->vci; + *vc_table = (vcc->vci << 6) | 15; + if (vcc->qos.rxtp.traffic_class == ATM_ABR) { + struct abr_vc_table *abr_vc_table = (struct abr_vc_table *) + (iadev->reass_ram+ABR_VC_TABLE*iadev->memSize); + abr_vc_table += vcc->vci; + abr_vc_table->rdf = 0x0003; + abr_vc_table->air = 0x5eb1; + } + // Drain the packets + rx_dle_intr(vcc->dev); + iadev->rx_open[vcc->vci] = 0; + } + kfree(INPH_IA_VCC(vcc)); + ia_vcc = NULL; + INPH_IA_VCC(vcc) = NULL; + vcc->flags &= ~ATM_VF_ADDR; + return; +} + +static int ia_open(struct atm_vcc *vcc, short vpi, int vci) +{ + IADEV *iadev; + struct ia_vcc *ia_vcc; + int error; + if (!(vcc->flags & ATM_VF_PARTIAL)) + { + IF_EVENT(printk("ia: not partially allocated resources\n");) + INPH_IA_VCC(vcc) = NULL; + } + iadev = INPH_IA_DEV(vcc->dev); + error = atm_find_ci(vcc, &vpi, &vci); + if (error) + { + printk("iadev: atm_find_ci returned error %d\n", error); + return error; + } + vcc->vpi = vpi; + vcc->vci = vci; + if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) + { + IF_EVENT(printk("iphase open: unspec part\n");) + vcc->flags |= ATM_VF_ADDR; + } + if (vcc->qos.aal != ATM_AAL5) + return -EINVAL; + IF_EVENT(printk(DEV_LABEL "(itf %d): open %d.%d\n", + vcc->dev->number, vcc->vpi, vcc->vci);) + + /* Device dependent initialization */ + ia_vcc = kmalloc(sizeof(struct ia_vcc), GFP_KERNEL); + if (!ia_vcc) return -ENOMEM; + INPH_IA_VCC(vcc) = ia_vcc; + + if ((error = open_rx(vcc))) + { + IF_EVENT(printk("iadev: error in open_rx, closing\n");) + ia_close(vcc); + return error; + } + + if ((error = open_tx(vcc))) + { + IF_EVENT(printk("iadev: error in open_tx, closing\n");) + ia_close(vcc); + return error; + } + + vcc->flags |= ATM_VF_READY; + +#ifndef MODULE + { + static u8 first = 1; + if (first) { + ia_timer.next = NULL; + ia_timer.prev = NULL; + ia_timer.expires = jiffies + 3*HZ; + ia_timer.data = 0UL; + ia_timer.function = ia_led_timer; + add_timer(&ia_timer); + first = 0; + } + } +#endif + IF_EVENT(printk("ia open returning\n");) + return 0; +} + +static int ia_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags) +{ + IF_EVENT(printk(">ia_change_qos\n");) + return 0; +} + +static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg) +{ + PIA_CMDBUF ia_cmds; + IADEV *iadev; + int i, board; + u16 *tmps; + IF_EVENT(printk(">ia_ioctl\n");) + if (cmd != IA_CMD) { + if (!dev->phy->ioctl) return -EINVAL; + return dev->phy->ioctl(dev,cmd,arg); + } + ia_cmds = (PIA_CMDBUF)arg; + board = ia_cmds->status; + if ((board < 0) || (board > iadev_count)) + board = 0; + iadev = ia_dev[board]; + switch (ia_cmds->cmd) { + case MEMDUMP: + { + switch (ia_cmds->sub_cmd) { + case MEMDUMP_DEV: + memcpy((char*)ia_cmds->buf, (char*)iadev, + sizeof(IADEV)); + ia_cmds->status = 0; + break; + case MEMDUMP_SEGREG: + tmps = (u16 *)ia_cmds->buf; + for(i=0; i<0x80; i+=2, tmps++) + *tmps = *(u16*)(iadev->seg_reg+i); + ia_cmds->status = 0; + ia_cmds->len = 0x80; + break; + case MEMDUMP_REASSREG: + tmps = (u16 *)ia_cmds->buf; + for(i=0; i<0x80; i+=2, tmps++) + *tmps = *(u16*)(iadev->reass_reg+i); + ia_cmds->status = 0; + ia_cmds->len = 0x80; + break; + case MEMDUMP_FFL: + { + ia_regs_t regs_local; + ffredn_t *ffL = ®s_local.ffredn; + rfredn_t *rfL = ®s_local.rfredn; + + /* Copy real rfred registers into the local copy */ + for (i=0; i<(sizeof (rfredn_t))/4; i++) + ((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff; + /* Copy real ffred registers into the local copy */ + for (i=0; i<(sizeof (ffredn_t))/4; i++) + ((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff; + + memcpy((char*)ia_cmds->buf,(char*)®s_local,sizeof(ia_regs_t)); + printk("Board %d registers dumped\n", board); + ia_cmds->status = 0; + } + break; + case READ_REG: + { + desc_dbg(iadev); + ia_cmds->status = 0; + } + break; + case 0x6: + { + ia_cmds->status = 0; + printk("skb = 0x%lx\n", (long)skb_peek(&iadev->tx_backlog)); + printk("rtn_q: 0x%lx\n",(long)ia_deque_rtn_q(&iadev->tx_return_q)); + } + break; + case 0x8: + { + struct sonet_stats *stats; + stats = &PRIV(_ia_dev[board])->sonet_stats; + printk("section_bip: %d\n", stats->section_bip); + printk("line_bip : %d\n", stats->line_bip); + printk("path_bip : %d\n", stats->path_bip); + printk("line_febe : %d\n", stats->line_febe); + printk("path_febe : %d\n", stats->path_febe); + printk("corr_hcs : %d\n", stats->corr_hcs); + printk("uncorr_hcs : %d\n", stats->uncorr_hcs); + printk("tx_cells : %d\n", stats->tx_cells); + printk("rx_cells : %d\n", stats->rx_cells); + } + ia_cmds->status = 0; + break; + case 0x9: + for (i = 1; i <= iadev->num_rx_desc; i++) + free_desc(_ia_dev[board], i); + writew( ~(RX_FREEQ_EMPT | RX_EXCP_RCVD), + iadev->reass_reg+REASS_MASK_REG); + iadev->rxing = 1; + + ia_cmds->status = 0; + break; + + case 0xb: + IaFrontEndIntr(iadev); + break; + case 0xa: + { + ia_cmds->status = 0; + IADebugFlag = ia_cmds->maddr; + printk("New debug option loaded\n"); + } + break; + default: + memcpy((char*)ia_cmds->buf, (char*)ia_cmds->maddr, ia_cmds->len); + ia_cmds->status = 0; + break; + } + } + break; + default: + break; + + } + return 0; +} + +static int ia_getsockopt(struct atm_vcc *vcc, int level, int optname, + void *optval, int optlen) +{ + IF_EVENT(printk(">ia_getsockopt\n");) + return -EINVAL; +} + +static int ia_setsockopt(struct atm_vcc *vcc, int level, int optname, + void *optval, int optlen) +{ + IF_EVENT(printk(">ia_setsockopt\n");) + return -EINVAL; +} + +static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { + IADEV *iadev; + struct dle *wr_ptr; + struct tx_buf_desc *buf_desc_ptr; + int desc; + int comp_code; + unsigned int addr; + int total_len, pad, last; + struct cpcs_trailer *trailer; + struct ia_vcc *iavcc; + iadev = INPH_IA_DEV(vcc->dev); + iavcc = INPH_IA_VCC(vcc); + if (!iavcc->txing) { + printk("discard packet on closed VC\n"); + if (vcc->pop) vcc->pop(vcc, skb); + else dev_kfree_skb(skb); + } + + if (skb->len > iadev->tx_buf_sz - 8) { + printk("Transmit size over tx buffer size\n"); + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + return 0; + } + if ((u32)skb->data & 3) { + printk("Misaligned SKB\n"); + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + return 0; + } + /* Get a descriptor number from our free descriptor queue + We get the descr number from the TCQ now, since I am using + the TCQ as a free buffer queue. Initially TCQ will be + initialized with all the descriptors and is hence, full. + */ + desc = get_desc (iadev, iavcc); + if (desc == 0xffff) + return 1; + comp_code = desc >> 13; + desc &= 0x1fff; + + if ((desc == 0) || (desc > iadev->num_tx_desc)) + { + IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);) + vcc->stats->tx++; + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + return 0; /* return SUCCESS */ + } + + if (comp_code) + { + IF_ERR(printk(DEV_LABEL "send desc:%d completion code %d error\n", + desc, comp_code);) + } + + /* remember the desc and vcc mapping */ + iavcc->vc_desc_cnt++; + iadev->desc_tbl[desc-1].iavcc = iavcc; + iadev->desc_tbl[desc-1].txskb = skb; + IA_SKB_STATE(skb) = 0; + + iadev->ffL.tcq_rd += 2; + if (iadev->ffL.tcq_rd > iadev->ffL.tcq_ed) + iadev->ffL.tcq_rd = iadev->ffL.tcq_st; + writew(iadev->ffL.tcq_rd, iadev->seg_reg+TCQ_RD_PTR); + + /* Put the descriptor number in the packet ready queue + and put the updated write pointer in the DLE field + */ + *(u16*)(iadev->seg_ram+iadev->ffL.prq_wr) = desc; + + iadev->ffL.prq_wr += 2; + if (iadev->ffL.prq_wr > iadev->ffL.prq_ed) + iadev->ffL.prq_wr = iadev->ffL.prq_st; + + /* Figure out the exact length of the packet and padding required to + make it aligned on a 48 byte boundary. */ + total_len = skb->len + sizeof(struct cpcs_trailer); + last = total_len - (total_len/48)*48; + pad = 48 - last; + total_len = pad + total_len; + IF_TX(printk("ia packet len:%d padding:%d\n", total_len, pad);) + + /* Put the packet in a tx buffer */ + if (!iadev->tx_buf[desc-1]) + printk("couldn't get free page\n"); + + IF_TX(printk("Sent: skb = 0x%x skb->data: 0x%x len: %d, desc: %d\n", + (u32)skb, (u32)skb->data, skb->len, desc);) + addr = virt_to_bus(skb->data); + trailer = (struct cpcs_trailer*)iadev->tx_buf[desc-1]; + trailer->control = 0; + /*big endian*/ + trailer->length = ((skb->len & 0xff) << 8) | ((skb->len & 0xff00) >> 8); + trailer->crc32 = 0; /* not needed - dummy bytes */ + + /* Display the packet */ + IF_TXPKT(printk("Sent data: len = %d MsgNum = %d\n", + skb->len, tcnter++); + xdump(skb->data, skb->len, "TX: "); + printk("\n");) + + /* Build the buffer descriptor */ + buf_desc_ptr = (struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE); + buf_desc_ptr += desc; /* points to the corresponding entry */ + buf_desc_ptr->desc_mode = AAL5 | EOM_EN | APP_CRC32 | CMPL_INT; + writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); + buf_desc_ptr->vc_index = vcc->vci; + buf_desc_ptr->bytes = total_len; + + if (vcc->qos.txtp.traffic_class == ATM_ABR) + clear_lockup (vcc, iadev); + + /* Build the DLE structure */ + wr_ptr = iadev->tx_dle_q.write; + memset((caddr_t)wr_ptr, 0, sizeof(struct dle)); + wr_ptr->sys_pkt_addr = addr; + wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | + buf_desc_ptr->buf_start_lo; + /* wr_ptr->bytes = swap(total_len); didn't seem to affect ?? */ + wr_ptr->bytes = skb->len; + + /* hw bug - DLEs of 0x2d, 0x2e, 0x2f cause DMA lockup */ + if ((wr_ptr->bytes >> 2) == 0xb) + wr_ptr->bytes = 0x30; + + wr_ptr->mode = TX_DLE_PSI; + wr_ptr->prq_wr_ptr_data = 0; + + /* end is not to be used for the DLE q */ + if (++wr_ptr == iadev->tx_dle_q.end) + wr_ptr = iadev->tx_dle_q.start; + + /* Build trailer dle */ + wr_ptr->sys_pkt_addr = virt_to_bus(iadev->tx_buf[desc-1]); + wr_ptr->local_pkt_addr = ((buf_desc_ptr->buf_start_hi << 16) | + buf_desc_ptr->buf_start_lo) + total_len - sizeof(struct cpcs_trailer); + + wr_ptr->bytes = sizeof(struct cpcs_trailer); + wr_ptr->mode = DMA_INT_ENABLE; + wr_ptr->prq_wr_ptr_data = iadev->ffL.prq_wr; + + /* end is not to be used for the DLE q */ + if (++wr_ptr == iadev->tx_dle_q.end) + wr_ptr = iadev->tx_dle_q.start; + + iadev->tx_dle_q.write = wr_ptr; + ATM_DESC(skb) = vcc->vci; + skb_queue_tail(&iadev->tx_dma_q, skb); + + vcc->stats->tx++; + iadev->tx_pkt_cnt++; + /* Increment transaction counter */ + writel(2, iadev->dma+IPHASE5575_TX_COUNTER); + +#if 0 + /* add flow control logic */ + if (vcc->stats->tx % 20 == 0) { + if (iavcc->vc_desc_cnt > 10) { + vcc->tx_quota = vcc->tx_quota * 3 / 4; + printk("Tx1: vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); + iavcc->flow_inc = -1; + iavcc->saved_tx_quota = vcc->tx_quota; + } else if ((iavcc->flow_inc < 0) && (iavcc->vc_desc_cnt < 3)) { + // vcc->tx_quota = 3 * iavcc->saved_tx_quota / 4; + printk("Tx2: vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); + iavcc->flow_inc = 0; + } + } +#endif + IF_TX(printk("ia send done\n");) + return 0; +} + +static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + IADEV *iadev; + struct ia_vcc *iavcc; + unsigned long flags; + + iadev = INPH_IA_DEV(vcc->dev); + iavcc = INPH_IA_VCC(vcc); + if ((!skb)||(skb->len>(iadev->tx_buf_sz-sizeof(struct cpcs_trailer)))) + { + if (!skb) + printk(KERN_CRIT "null skb in ia_send\n"); + dev_kfree_skb(skb); + return -EINVAL; + } + spin_lock_irqsave(&iadev->tx_lock, flags); + if ((vcc->flags & ATM_VF_READY) == 0){ + dev_kfree_skb(skb); + spin_unlock_irqrestore(&iadev->tx_lock, flags); + return -EINVAL; + } + ATM_SKB(skb)->vcc = vcc; + + if (skb_peek(&iadev->tx_backlog)) { + skb_queue_tail(&iadev->tx_backlog, skb); + } + else { + if (ia_pkt_tx (vcc, skb)) { + skb_queue_tail(&iadev->tx_backlog, skb); + } + } + spin_unlock_irqrestore(&iadev->tx_lock, flags); + return 0; + +} + +static int ia_sg_send(struct atm_vcc *vcc, unsigned long start, + unsigned long size) +{ + IF_EVENT(printk(">ia_sg_send\n");) + return 0; +} + + +static int ia_proc_read(struct atm_dev *dev,loff_t *pos,char *page) +{ + int left = *pos, n; + char *tmpPtr; + IADEV *iadev = INPH_IA_DEV(dev); + if(!left--) { + if (iadev->phy_type == FE_25MBIT_PHY) { + n = sprintf(page, " Board Type : Iphase5525-1KVC-128K\n"); + return n; + } + if (iadev->phy_type == FE_DS3_PHY) + n = sprintf(page, " Board Type : Iphase-ATM-DS3"); + else if (iadev->phy_type == FE_E3_PHY) + n = sprintf(page, " Board Type : Iphase-ATM-E3"); + else if (iadev->phy_type == FE_UTP_OPTION) + n = sprintf(page, " Board Type : Iphase-ATM-UTP155"); + else + n = sprintf(page, " Board Type : Iphase-ATM-OC3"); + tmpPtr = page + n; + if (iadev->pci_map_size == 0x40000) + n += sprintf(tmpPtr, "-1KVC-"); + else + n += sprintf(tmpPtr, "-4KVC-"); + tmpPtr = page + n; + if ((iadev->memType & MEM_SIZE_MASK) == MEM_SIZE_1M) + n += sprintf(tmpPtr, "1M \n"); + else if ((iadev->memType & MEM_SIZE_MASK) == MEM_SIZE_512K) + n += sprintf(tmpPtr, "512K\n"); + else + n += sprintf(tmpPtr, "128K\n"); + return n; + } + if (!left) { + return sprintf(page, " Number of Tx Buffer: %u\n" + " Size of Tx Buffer : %u\n" + " Number of Rx Buffer: %u\n" + " Size of Rx Buffer : %u\n" + " Packets Receiverd : %u\n" + " Packets Transmitted: %u\n" + " Cells Received : %u\n" + " Cells Transmitted : %u\n" + " Board Dropped Cells: %u\n" + " Board Dropped Pkts : %u\n", + iadev->num_tx_desc, iadev->tx_buf_sz, + iadev->num_rx_desc, iadev->rx_buf_sz, + iadev->rx_pkt_cnt, iadev->tx_pkt_cnt, + iadev->rx_cell_cnt, iadev->tx_cell_cnt, + iadev->drop_rxcell, iadev->drop_rxpkt); + } + return 0; +} + +static const struct atmdev_ops ops = { + open: ia_open, + close: ia_close, + ioctl: ia_ioctl, + getsockopt: ia_getsockopt, + setsockopt: ia_setsockopt, + send: ia_send, + sg_send: ia_sg_send, + phy_put: ia_phy_put, + phy_get: ia_phy_get, + change_qos: ia_change_qos, + proc_read: ia_proc_read +}; + + +#if LINUX_VERSION_CODE >= 0x20312 +int __init ia_detect(void) +#else +__initfunc(int ia_detect(void)) +#endif +{ + struct atm_dev *dev; + IADEV *iadev; + unsigned long flags; + int index = 0; + struct pci_dev *prev_dev; + if (!pci_present()) { + printk(KERN_ERR DEV_LABEL " driver but no PCI BIOS ?\n"); + return 0; + } + iadev = (IADEV *)kmalloc(sizeof(IADEV), GFP_KERNEL); + if (!iadev) return -ENOMEM; + memset((char*)iadev, 0, sizeof(IADEV)); + prev_dev = NULL; + while((iadev->pci = pci_find_device(PCI_VENDOR_ID_IPHASE, + PCI_DEVICE_ID_IPHASE_5575, prev_dev))) { + IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n", + iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn), + PCI_FUNC(iadev->pci->devfn));) + dev = atm_dev_register(DEV_LABEL, &ops, -1, 0); + if (!dev) break; + IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", + dev->number);) + INPH_IA_DEV(dev) = iadev; + // TODO: multi_board using ia_boards logic in cleanup_module + ia_dev[index] = iadev; + _ia_dev[index] = dev; + IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", + (u32)dev, iadev->LineRate);) + iadev_count++; + spin_lock_init(&iadev->misc_lock); + spin_lock_irqsave(&iadev->misc_lock, flags); + if (ia_init(dev) || ia_start(dev)) { + atm_dev_deregister(dev); + IF_INIT(printk("IA register failed!\n");) + ia_dev[index] = NULL; + _ia_dev[index] = NULL; + iadev_count--; + spin_unlock_irqrestore(&iadev->misc_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&iadev->misc_lock, flags); + IF_EVENT(printk("iadev_count = %d\n", iadev_count);) + prev_dev = iadev->pci; + iadev->next_board = ia_boards; + ia_boards = dev; + iadev = (IADEV *)kmalloc( + sizeof(IADEV), GFP_KERNEL); + if (!iadev) break; + memset((char*)iadev, 0, sizeof(IADEV)); + index++; + dev = NULL; + } + return index; +} + + +#ifdef MODULE + +int init_module(void) +{ + IF_EVENT(printk(">ia init_module\n");) + if (!ia_detect()) { + printk(KERN_ERR DEV_LABEL ": no adapter found\n"); + return -ENXIO; + } + // MOD_INC_USE_COUNT; + ia_timer.next = NULL; + ia_timer.prev = NULL; + ia_timer.expires = jiffies + 3*HZ; + ia_timer.data = 0UL; + ia_timer.function = ia_led_timer; + add_timer(&ia_timer); + + return 0; +} + + +void cleanup_module(void) +{ + struct atm_dev *dev; + IADEV *iadev; + unsigned short command; + int i, j= 0; + + IF_EVENT(printk(">ia cleanup_module\n");) + // MOD_DEC_USE_COUNT; + if (MOD_IN_USE) + printk("ia: module in use\n"); + del_timer(&ia_timer); + while(ia_dev[j]) + { + dev = ia_boards; + iadev = INPH_IA_DEV(dev); + ia_boards = iadev->next_board; + + /* disable interrupt of lost signal */ + ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10); + udelay(1); + + /* De-register device */ + atm_dev_deregister(dev); + IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);) + for (i= 0; i< iadev->num_tx_desc; i++) + kfree(iadev->tx_buf[i]); + kfree(iadev->tx_buf); + /* Disable memory mapping and busmastering */ + if (pci_read_config_word(iadev->pci, + PCI_COMMAND, &command) != 0) + { + printk("ia: can't read PCI_COMMAND.\n"); + } + command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + if (pci_write_config_word(iadev->pci, + PCI_COMMAND, command) != 0) + { + printk("ia: can't write PCI_COMMAND.\n"); + } + free_irq(iadev->irq, dev); + iounmap((void *) iadev->base); + kfree(iadev); + j++; + } + /* and voila whatever we tried seems to work. I don't know if it will + fix suni errors though. Really doubt that. */ + for (i = 0; i<8; i++) { + ia_dev[i] = NULL; + _ia_dev[i] = NULL; + } +} + +#endif + diff -u --recursive --new-file v2.3.42/linux/drivers/atm/iphase.h linux/drivers/atm/iphase.h --- v2.3.42/linux/drivers/atm/iphase.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/iphase.h Tue Feb 8 18:48:22 2000 @@ -0,0 +1,1467 @@ +/****************************************************************************** + Device driver for Interphase ATM PCI adapter cards + Author: Peter Wang + Interphase Corporation + Version: 1.0 + iphase.h: This is the header file for iphase.c. +******************************************************************************* + + This software may be used and distributed according to the terms + of the GNU Public License (GPL), incorporated herein by reference. + Drivers based on this skeleton fall under the GPL and must retain + the authorship (implicit copyright) notice. + + 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. + + Modified from an incomplete driver for Interphase 5575 1KVC 1M card which + was originally written by Monalisa Agrawal at UNH. Now this driver + supports a variety of varients of Interphase ATM PCI (i)Chip adapter + card family (See www.iphase.com/products/ClassSheet.cfm?ClassID=ATM) + in terms of PHY type, the size of control memory and the size of + packet memory. The followings are the change log and history: + + Bugfix the Mona's UBR driver. + Modify the basic memory allocation and dma logic. + Port the driver to the latest kernel from 2.0.46. + Complete the ABR logic of the driver, and added the ABR work- + around for the hardware anormalies. + Add the CBR support. + Add the flow control logic to the driver to allow rate-limit VC. + Add 4K VC support to the board with 512K control memory. + Add the support of all the variants of the Interphase ATM PCI + (i)Chip adapter cards including x575 (155M OC3 and UTP155), x525 + (25M UTP25) and x531 (DS3 and E3). + Add SMP support. + + Support and updates available at: ftp://ftp.iphase.com/pub/atm + +*******************************************************************************/ + +#ifndef IPHASE_H +#define IPHASE_H + +#include + +/************************ IADBG DEFINE *********************************/ +/* IADebugFlag Bit Map */ +#define IF_IADBG_INIT_ADAPTER 0x00000001 // init adapter info +#define IF_IADBG_TX 0x00000002 // debug TX +#define IF_IADBG_RX 0x00000004 // debug RX +#define IF_IADBG_QUERY_INFO 0x00000008 // debug Request call +#define IF_IADBG_SHUTDOWN 0x00000010 // debug shutdown event +#define IF_IADBG_INTR 0x00000020 // debug interrupt DPC +#define IF_IADBG_TXPKT 0x00000040 // debug TX PKT +#define IF_IADBG_RXPKT 0x00000080 // debug RX PKT +#define IF_IADBG_ERR 0x00000100 // debug system error +#define IF_IADBG_EVENT 0x00000200 // debug event +#define IF_IADBG_DIS_INTR 0x00001000 // debug disable interrupt +#define IF_IADBG_EN_INTR 0x00002000 // debug enable interrupt +#define IF_IADBG_LOUD 0x00004000 // debugging info +#define IF_IADBG_VERY_LOUD 0x00008000 // excessive debugging info +#define IF_IADBG_CBR 0x00100000 // +#define IF_IADBG_UBR 0x00200000 // +#define IF_IADBG_ABR 0x00400000 // +#define IF_IADBG_DESC 0x01000000 // +#define IF_IADBG_SUNI_STAT 0x02000000 // suni statistics +#define IF_IADBG_RESET 0x04000000 + +extern unsigned int IADebugFlag; + +#define IF_IADBG(f) if (IADebugFlag & (f)) + +#ifdef CONFIG_ATM_IA_DEBUG /* Debug build */ + +#define IF_LOUD(A) IF_IADBG(IF_IADBG_LOUD) { A } +#define IF_ERR(A) IF_IADBG(IF_IADBG_ERR) { A } +#define IF_VERY_LOUD(A) IF_IADBG( IF_IADBG_VERY_LOUD ) { A } + +#define IF_INIT_ADAPTER(A) IF_IADBG( IF_IADBG_INIT_ADAPTER ) { A } +#define IF_INIT(A) IF_IADBG( IF_IADBG_INIT_ADAPTER ) { A } +#define IF_SUNI_STAT(A) IF_IADBG( IF_IADBG_SUNI_STAT ) { A } +#define IF_QUERY_INFO(A) IF_IADBG( IF_IADBG_QUERY_INFO ) { A } +#define IF_COPY_OVER(A) IF_IADBG( IF_IADBG_COPY_OVER ) { A } + +#define IF_INTR(A) IF_IADBG( IF_IADBG_INTR ) { A } +#define IF_DIS_INTR(A) IF_IADBG( IF_IADBG_DIS_INTR ) { A } +#define IF_EN_INTR(A) IF_IADBG( IF_IADBG_EN_INTR ) { A } + +#define IF_TX(A) IF_IADBG( IF_IADBG_TX ) { A } +#define IF_RX(A) IF_IADBG( IF_IADBG_RX ) { A } +#define IF_TXPKT(A) IF_IADBG( IF_IADBG_TXPKT ) { A } +#define IF_RXPKT(A) IF_IADBG( IF_IADBG_RXPKT ) { A } + +#define IF_SHUTDOWN(A) IF_IADBG(IF_IADBG_SHUTDOWN) { A } +#define IF_CBR(A) IF_IADBG( IF_IADBG_CBR ) { A } +#define IF_UBR(A) IF_IADBG( IF_IADBG_UBR ) { A } +#define IF_ABR(A) IF_IADBG( IF_IADBG_ABR ) { A } +#define IF_EVENT(A) IF_IADBG( IF_IADBG_EVENT) { A } + +#else /* free build */ +#define IF_LOUD(A) +#define IF_VERY_LOUD(A) +#define IF_INIT_ADAPTER(A) +#define IF_INIT(A) +#define IF_SUNI_STAT(A) +#define IF_PVC_CHKPKT(A) +#define IF_QUERY_INFO(A) +#define IF_COPY_OVER(A) +#define IF_HANG(A) +#define IF_INTR(A) +#define IF_DIS_INTR(A) +#define IF_EN_INTR(A) +#define IF_TX(A) +#define IF_RX(A) +#define IF_TXDEBUG(A) +#define IF_VC(A) +#define IF_ERR(A) +#define IF_CBR(A) +#define IF_UBR(A) +#define IF_ABR(A) +#define IF_SHUTDOWN(A) +#define DbgPrint(A) +#define IF_EVENT(A) +#define IF_TXPKT(A) +#define IF_RXPKT(A) +#endif /* CONFIG_ATM_IA_DEBUG */ + +#define isprint(a) ((a >=' ')&&(a <= '~')) +#define ATM_DESC(skb) (skb->protocol) +#define IA_SKB_STATE(skb) (skb->protocol) +#define IA_DLED 1 +#define IA_TX_DONE 2 + +/* iadbg defines */ +#define IA_CMD 0x7749 +typedef struct { + int cmd; + int sub_cmd; + int len; + u32 maddr; + int status; + void *buf; +} IA_CMDBUF, *PIA_CMDBUF; + +/* cmds */ +#define MEMDUMP 0x01 + +/* sub_cmds */ +#define MEMDUMP_SEGREG 0x2 +#define MEMDUMP_DEV 0x1 +#define MEMDUMP_REASSREG 0x3 +#define MEMDUMP_FFL 0x4 +#define READ_REG 0x5 +#define WAKE_DBG_WAIT 0x6 + +/************************ IADBG DEFINE END ***************************/ + +#define Boolean(x) ((x) ? 1 : 0) +#define NR_VCI 1024 /* number of VCIs */ +#define NR_VCI_LD 10 /* log2(NR_VCI) */ +#define NR_VCI_4K 4096 /* number of VCIs */ +#define NR_VCI_4K_LD 12 /* log2(NR_VCI) */ +#define MEM_VALID 0xfffffff0 /* mask base address with this */ + +#ifndef PCI_VENDOR_ID_IPHASE +#define PCI_VENDOR_ID_IPHASE 0x107e +#endif +#ifndef PCI_DEVICE_ID_IPHASE_5575 +#define PCI_DEVICE_ID_IPHASE_5575 0x0008 +#endif +#define DEV_LABEL "ia" +#define PCR 207692 +#define ICR 100000 +#define MCR 0 +#define TBE 1000 +#define FRTT 1 +#define RIF 2 +#define RDF 4 +#define NRMCODE 5 /* 0 - 7 */ +#define TRMCODE 3 /* 0 - 7 */ +#define CDFCODE 6 +#define ATDFCODE 2 /* 0 - 15 */ + +/*---------------------- Packet/Cell Memory ------------------------*/ +#define TX_PACKET_RAM 0x00000 /* start of Trasnmit Packet memory - 0 */ +#define DFL_TX_BUF_SZ 10240 /* 10 K buffers */ +#define DFL_TX_BUFFERS 50 /* number of packet buffers for Tx + - descriptor 0 unused */ +#define REASS_RAM_SIZE 0x10000 /* for 64K 1K VC board */ +#define RX_PACKET_RAM 0x80000 /* start of Receive Packet memory - 512K */ +#define DFL_RX_BUF_SZ 10240 /* 10k buffers */ +#define DFL_RX_BUFFERS 50 /* number of packet buffers for Rx + - descriptor 0 unused */ + +struct cpcs_trailer +{ + u_short control; + u_short length; + u_int crc32; +}; + +struct ia_vcc +{ + int rxing; + int txing; + int NumCbrEntry; + u32 pcr; + u32 saved_tx_quota; + int flow_inc; + struct sk_buff_head txing_skb; + int ltimeout; + u8 vc_desc_cnt; + +}; + +struct abr_vc_table +{ + u_char status; + u_char rdf; + u_short air; + u_int res[3]; + u_int req_rm_cell_data1; + u_int req_rm_cell_data2; + u_int add_rm_cell_data1; + u_int add_rm_cell_data2; +}; + +/* 32 byte entries */ +struct main_vc +{ + u_short type; +#define ABR 0x8000 +#define UBR 0xc000 +#define CBR 0x0000 + /* ABR fields */ + u_short nrm; + u_short trm; + u_short rm_timestamp_hi; + u_short rm_timestamp_lo:8, + crm:8; + u_short remainder; /* ABR and UBR fields - last 10 bits*/ + u_short next_vc_sched; + u_short present_desc; /* all classes */ + u_short last_cell_slot; /* ABR and UBR */ + u_short pcr; + u_short fraction; + u_short icr; + u_short atdf; + u_short mcr; + u_short acr; + u_short unack:8, + status:8; /* all classes */ +#define UIOLI 0x80 +#define CRC_APPEND 0x40 /* for status field - CRC-32 append */ +#define ABR_STATE 0x02 + +}; + + +/* 8 byte entries */ +struct ext_vc +{ + u_short atm_hdr1; + u_short atm_hdr2; + u_short last_desc; + u_short out_of_rate_link; /* reserved for UBR and CBR */ +}; + + +#define DLE_ENTRIES 256 +#define DMA_INT_ENABLE 0x0002 /* use for both Tx and Rx */ +#define TX_DLE_PSI 0x0001 + +/* Descriptor List Entries (DLE) */ +struct dle +{ + u32 sys_pkt_addr; + u32 local_pkt_addr; + u32 bytes; + u16 prq_wr_ptr_data; + u16 mode; +}; + +struct dle_q +{ + struct dle *start; + struct dle *end; + struct dle *read; + struct dle *write; +}; + +struct free_desc_q +{ + int desc; /* Descriptor number */ + struct free_desc_q *next; +}; + +struct tx_buf_desc { + unsigned short desc_mode; + unsigned short vc_index; + unsigned short res1; /* reserved field */ + unsigned short bytes; + unsigned short buf_start_hi; + unsigned short buf_start_lo; + unsigned short res2[10]; /* reserved field */ +}; + + +struct rx_buf_desc { + unsigned short desc_mode; + unsigned short vc_index; + unsigned short vpi; + unsigned short bytes; + unsigned short buf_start_hi; + unsigned short buf_start_lo; + unsigned short dma_start_hi; + unsigned short dma_start_lo; + unsigned short crc_upper; + unsigned short crc_lower; + unsigned short res:8, timeout:8; + unsigned short res2[5]; /* reserved field */ +}; + +/*--------SAR stuff ---------------------*/ + +#define EPROM_SIZE 0x40000 /* says 64K in the docs ??? */ +#define MAC1_LEN 4 +#define MAC2_LEN 2 + +/*------------ PCI Memory Space Map, 128K SAR memory ----------------*/ +#define IPHASE5575_PCI_CONFIG_REG_BASE 0x0000 +#define IPHASE5575_BUS_CONTROL_REG_BASE 0x1000 /* offsets 0x00 - 0x3c */ +#define IPHASE5575_FRAG_CONTROL_REG_BASE 0x2000 +#define IPHASE5575_REASS_CONTROL_REG_BASE 0x3000 +#define IPHASE5575_DMA_CONTROL_REG_BASE 0x4000 +#define IPHASE5575_FRONT_END_REG_BASE IPHASE5575_DMA_CONTROL_REG_BASE +#define IPHASE5575_FRAG_CONTROL_RAM_BASE 0x10000 +#define IPHASE5575_REASS_CONTROL_RAM_BASE 0x20000 + +/*------------ Bus interface control registers -----------------*/ +#define IPHASE5575_BUS_CONTROL_REG 0x00 +#define IPHASE5575_BUS_STATUS_REG 0x01 /* actual offset 0x04 */ +#define IPHASE5575_MAC1 0x02 +#define IPHASE5575_REV 0x03 +#define IPHASE5575_MAC2 0x03 /*actual offset 0x0e-reg 0x0c*/ +#define IPHASE5575_EXT_RESET 0x04 +#define IPHASE5575_INT_RESET 0x05 /* addr 1c ?? reg 0x06 */ +#define IPHASE5575_PCI_ADDR_PAGE 0x07 /* reg 0x08, 0x09 ?? */ +#define IPHASE5575_EEPROM_ACCESS 0x0a /* actual offset 0x28 */ +#define IPHASE5575_CELL_FIFO_QUEUE_SZ 0x0b +#define IPHASE5575_CELL_FIFO_MARK_STATE 0x0c +#define IPHASE5575_CELL_FIFO_READ_PTR 0x0d +#define IPHASE5575_CELL_FIFO_WRITE_PTR 0x0e +#define IPHASE5575_CELL_FIFO_CELLS_AVL 0x0f /* actual offset 0x3c */ + +/* Bus Interface Control Register bits */ +#define CTRL_FE_RST 0x80000000 +#define CTRL_LED 0x40000000 +#define CTRL_25MBPHY 0x10000000 +#define CTRL_ENCMBMEM 0x08000000 +#define CTRL_ENOFFSEG 0x01000000 +#define CTRL_ERRMASK 0x00400000 +#define CTRL_DLETMASK 0x00100000 +#define CTRL_DLERMASK 0x00080000 +#define CTRL_FEMASK 0x00040000 +#define CTRL_SEGMASK 0x00020000 +#define CTRL_REASSMASK 0x00010000 +#define CTRL_CSPREEMPT 0x00002000 +#define CTRL_B128 0x00000200 +#define CTRL_B64 0x00000100 +#define CTRL_B48 0x00000080 +#define CTRL_B32 0x00000040 +#define CTRL_B16 0x00000020 +#define CTRL_B8 0x00000010 + +/* Bus Interface Status Register bits */ +#define STAT_CMEMSIZ 0xc0000000 +#define STAT_ADPARCK 0x20000000 +#define STAT_RESVD 0x1fffff80 +#define STAT_ERRINT 0x00000040 +#define STAT_MARKINT 0x00000020 +#define STAT_DLETINT 0x00000010 +#define STAT_DLERINT 0x00000008 +#define STAT_FEINT 0x00000004 +#define STAT_SEGINT 0x00000002 +#define STAT_REASSINT 0x00000001 + + +/*--------------- Segmentation control registers -----------------*/ +/* The segmentation registers are 16 bits access and the addresses + are defined as such so the addresses are the actual "offsets" */ +#define IDLEHEADHI 0x00 +#define IDLEHEADLO 0x01 +#define MAXRATE 0x02 +/* Values for MAXRATE register for 155Mbps and 25.6 Mbps operation */ +#define RATE155 0x64b1 // 16 bits float format +#define MAX_ATM_155 352768 // Cells/second p.118 +#define RATE25 0x5f9d + +#define STPARMS 0x03 +#define STPARMS_1K 0x008c +#define STPARMS_2K 0x0049 +#define STPARMS_4K 0x0026 +#define COMP_EN 0x4000 +#define CBR_EN 0x2000 +#define ABR_EN 0x0800 +#define UBR_EN 0x0400 + +#define ABRUBR_ARB 0x04 +#define RM_TYPE 0x05 +/*Value for RM_TYPE register for ATM Forum Traffic Mangement4.0 support*/ +#define RM_TYPE_4_0 0x0100 + +#define SEG_COMMAND_REG 0x17 +/* Values for the command register */ +#define RESET_SEG 0x0055 +#define RESET_SEG_STATE 0x00aa +#define RESET_TX_CELL_CTR 0x00cc + +#define CBR_PTR_BASE 0x20 +#define ABR_SBPTR_BASE 0x22 +#define UBR_SBPTR_BASE 0x23 +#define ABRWQ_BASE 0x26 +#define UBRWQ_BASE 0x27 +#define VCT_BASE 0x28 +#define VCTE_BASE 0x29 +#define CBR_TAB_BEG 0x2c +#define CBR_TAB_END 0x2d +#define PRQ_ST_ADR 0x30 +#define PRQ_ED_ADR 0x31 +#define PRQ_RD_PTR 0x32 +#define PRQ_WR_PTR 0x33 +#define TCQ_ST_ADR 0x34 +#define TCQ_ED_ADR 0x35 +#define TCQ_RD_PTR 0x36 +#define TCQ_WR_PTR 0x37 +#define SEG_QUEUE_BASE 0x40 +#define SEG_DESC_BASE 0x41 +#define MODE_REG_0 0x45 +#define T_ONLINE 0x0002 /* (i)chipSAR is online */ + +#define MODE_REG_1 0x46 +#define MODE_REG_1_VAL 0x0400 /*for propoer device operation*/ + +#define SEG_INTR_STATUS_REG 0x47 +#define SEG_MASK_REG 0x48 +#define TRANSMIT_DONE 0x0200 +#define TCQ_NOT_EMPTY 0x1000 /* this can be used for both the interrupt + status registers as well as the mask register */ + +#define CELL_CTR_HIGH_AUTO 0x49 +#define CELL_CTR_HIGH_NOAUTO 0xc9 +#define CELL_CTR_LO_AUTO 0x4a +#define CELL_CTR_LO_NOAUTO 0xca + +/* Diagnostic registers */ +#define NEXTDESC 0x59 +#define NEXTVC 0x5a +#define PSLOTCNT 0x5d +#define NEWDN 0x6a +#define NEWVC 0x6b +#define SBPTR 0x6c +#define ABRWQ_WRPTR 0x6f +#define ABRWQ_RDPTR 0x70 +#define UBRWQ_WRPTR 0x71 +#define UBRWQ_RDPTR 0x72 +#define CBR_VC 0x73 +#define ABR_SBVC 0x75 +#define UBR_SBVC 0x76 +#define ABRNEXTLINK 0x78 +#define UBRNEXTLINK 0x79 + + +/*----------------- Reassembly control registers ---------------------*/ +/* The reassembly registers are 16 bits access and the addresses + are defined as such so the addresses are the actual "offsets" */ +#define MODE_REG 0x00 +#define R_ONLINE 0x0002 /* (i)chip is online */ +#define IGN_RAW_FL 0x0004 + +#define PROTOCOL_ID 0x01 +#define REASS_MASK_REG 0x02 +#define REASS_INTR_STATUS_REG 0x03 +/* Interrupt Status register bits */ +#define RX_PKT_CTR_OF 0x8000 +#define RX_ERR_CTR_OF 0x4000 +#define RX_CELL_CTR_OF 0x1000 +#define RX_FREEQ_EMPT 0x0200 +#define RX_EXCPQ_FL 0x0080 +#define RX_RAWQ_FL 0x0010 +#define RX_EXCP_RCVD 0x0008 +#define RX_PKT_RCVD 0x0004 +#define RX_RAW_RCVD 0x0001 + +#define DRP_PKT_CNTR 0x04 +#define ERR_CNTR 0x05 +#define RAW_BASE_ADR 0x08 +#define CELL_CTR0 0x0c +#define CELL_CTR1 0x0d +#define REASS_COMMAND_REG 0x0f +/* Values for command register */ +#define RESET_REASS 0x0055 +#define RESET_REASS_STATE 0x00aa +#define RESET_DRP_PKT_CNTR 0x00f1 +#define RESET_ERR_CNTR 0x00f2 +#define RESET_CELL_CNTR 0x00f8 +#define RESET_REASS_ALL_REGS 0x00ff + +#define REASS_DESC_BASE 0x10 +#define VC_LKUP_BASE 0x11 +#define REASS_TABLE_BASE 0x12 +#define REASS_QUEUE_BASE 0x13 +#define PKT_TM_CNT 0x16 +#define TMOUT_RANGE 0x17 +#define INTRVL_CNTR 0x18 +#define TMOUT_INDX 0x19 +#define VP_LKUP_BASE 0x1c +#define VP_FILTER 0x1d +#define ABR_LKUP_BASE 0x1e +#define FREEQ_ST_ADR 0x24 +#define FREEQ_ED_ADR 0x25 +#define FREEQ_RD_PTR 0x26 +#define FREEQ_WR_PTR 0x27 +#define PCQ_ST_ADR 0x28 +#define PCQ_ED_ADR 0x29 +#define PCQ_RD_PTR 0x2a +#define PCQ_WR_PTR 0x2b +#define EXCP_Q_ST_ADR 0x2c +#define EXCP_Q_ED_ADR 0x2d +#define EXCP_Q_RD_PTR 0x2e +#define EXCP_Q_WR_PTR 0x2f +#define CC_FIFO_ST_ADR 0x34 +#define CC_FIFO_ED_ADR 0x35 +#define CC_FIFO_RD_PTR 0x36 +#define CC_FIFO_WR_PTR 0x37 +#define STATE_REG 0x38 +#define BUF_SIZE 0x42 +#define XTRA_RM_OFFSET 0x44 +#define DRP_PKT_CNTR_NC 0x84 +#define ERR_CNTR_NC 0x85 +#define CELL_CNTR0_NC 0x8c +#define CELL_CNTR1_NC 0x8d + +/* State Register bits */ +#define EXCPQ_EMPTY 0x0040 +#define PCQ_EMPTY 0x0010 +#define FREEQ_EMPTY 0x0004 + + +/*----------------- Front End registers/ DMA control --------------*/ +/* There is a lot of documentation error regarding these offsets ??? + eg:- 2 offsets given 800, a00 for rx counter + similarly many others + Remember again that the offsets are to be 4*register number, so + correct the #defines here +*/ +#define IPHASE5575_TX_COUNTER 0x200 /* offset - 0x800 */ +#define IPHASE5575_RX_COUNTER 0x280 /* offset - 0xa00 */ +#define IPHASE5575_TX_LIST_ADDR 0x300 /* offset - 0xc00 */ +#define IPHASE5575_RX_LIST_ADDR 0x380 /* offset - 0xe00 */ + +/*--------------------------- RAM ---------------------------*/ +/* These memory maps are actually offsets from the segmentation and reassembly RAM base addresses */ + +/* Segmentation Control Memory map */ +#define TX_DESC_BASE 0x0000 /* Buffer Decriptor Table */ +#define TX_COMP_Q 0x1000 /* Transmit Complete Queue */ +#define PKT_RDY_Q 0x1400 /* Packet Ready Queue */ +#define CBR_SCHED_TABLE 0x1800 /* CBR Table */ +#define UBR_SCHED_TABLE 0x3000 /* UBR Table */ +#define UBR_WAIT_Q 0x4000 /* UBR Wait Queue */ +#define ABR_SCHED_TABLE 0x5000 /* ABR Table */ +#define ABR_WAIT_Q 0x5800 /* ABR Wait Queue */ +#define EXT_VC_TABLE 0x6000 /* Extended VC Table */ +#define MAIN_VC_TABLE 0x8000 /* Main VC Table */ +#define SCHEDSZ 1024 /* ABR and UBR Scheduling Table size */ +#define TX_DESC_TABLE_SZ 128 /* Number of entries in the Transmit + Buffer Descriptor Table */ + +/* These are used as table offsets in Descriptor Table address generation */ +#define DESC_MODE 0x0 +#define VC_INDEX 0x1 +#define BYTE_CNT 0x3 +#define PKT_START_HI 0x4 +#define PKT_START_LO 0x5 + +/* Descriptor Mode Word Bits */ +#define EOM_EN 0x0800 +#define AAL5 0x0100 +#define APP_CRC32 0x0400 +#define CMPL_INT 0x1000 + +#define TABLE_ADDRESS(db, dn, to) \ + (((unsigned long)(db & 0x04)) << 16) | (dn << 5) | (to << 1) + +/* Reassembly Control Memory Map */ +#define RX_DESC_BASE 0x0000 /* Buffer Descriptor Table */ +#define VP_TABLE 0x5c00 /* VP Table */ +#define EXCEPTION_Q 0x5e00 /* Exception Queue */ +#define FREE_BUF_DESC_Q 0x6000 /* Free Buffer Descriptor Queue */ +#define PKT_COMP_Q 0x6800 /* Packet Complete Queue */ +#define REASS_TABLE 0x7000 /* Reassembly Table */ +#define RX_VC_TABLE 0x7800 /* VC Table */ +#define ABR_VC_TABLE 0x8000 /* ABR VC Table */ +#define RX_DESC_TABLE_SZ 736 /* Number of entries in the Receive + Buffer Descriptor Table */ +#define VP_TABLE_SZ 256 /* Number of entries in VPTable */ +#define RX_VC_TABLE_SZ 1024 /* Number of entries in VC Table */ +#define REASS_TABLE_SZ 1024 /* Number of entries in Reassembly Table */ + /* Buffer Descriptor Table */ +#define RX_ACT 0x8000 +#define RX_VPVC 0x4000 +#define RX_CNG 0x0040 +#define RX_CER 0x0008 +#define RX_PTE 0x0004 +#define RX_OFL 0x0002 +#define NUM_RX_EXCP 32 + +/* Reassembly Table */ +#define NO_AAL5_PKT 0x0000 +#define AAL5_PKT_REASSEMBLED 0x4000 +#define AAL5_PKT_TERMINATED 0x8000 +#define RAW_PKT 0xc000 +#define REASS_ABR 0x2000 + +/*-------------------- Base Registers --------------------*/ +#define REG_BASE IPHASE5575_BUS_CONTROL_REG_BASE +#define RAM_BASE IPHASE5575_FRAG_CONTROL_RAM_BASE +#define PHY_BASE IPHASE5575_FRONT_END_REG_BASE +#define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE +#define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE + +typedef volatile u_int freg_t; +typedef u_int rreg_t; + +typedef struct _ffredn_t { + freg_t idlehead_high; /* Idle cell header (high) */ + freg_t idlehead_low; /* Idle cell header (low) */ + freg_t maxrate; /* Maximum rate */ + freg_t stparms; /* Traffic Management Parameters */ + freg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */ + freg_t rm_type; /* */ + u_int filler5[0x17 - 0x06]; + freg_t cmd_reg; /* Command register */ + u_int filler18[0x20 - 0x18]; + freg_t cbr_base; /* CBR Pointer Base */ + freg_t vbr_base; /* VBR Pointer Base */ + freg_t abr_base; /* ABR Pointer Base */ + freg_t ubr_base; /* UBR Pointer Base */ + u_int filler24; + freg_t vbrwq_base; /* VBR Wait Queue Base */ + freg_t abrwq_base; /* ABR Wait Queue Base */ + freg_t ubrwq_base; /* UBR Wait Queue Base */ + freg_t vct_base; /* Main VC Table Base */ + freg_t vcte_base; /* Extended Main VC Table Base */ + u_int filler2a[0x2C - 0x2A]; + freg_t cbr_tab_beg; /* CBR Table Begin */ + freg_t cbr_tab_end; /* CBR Table End */ + freg_t cbr_pointer; /* CBR Pointer */ + u_int filler2f[0x30 - 0x2F]; + freg_t prq_st_adr; /* Packet Ready Queue Start Address */ + freg_t prq_ed_adr; /* Packet Ready Queue End Address */ + freg_t prq_rd_ptr; /* Packet Ready Queue read pointer */ + freg_t prq_wr_ptr; /* Packet Ready Queue write pointer */ + freg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/ + freg_t tcq_ed_adr; /* Transmit Complete Queue End Address */ + freg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */ + freg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/ + u_int filler38[0x40 - 0x38]; + freg_t queue_base; /* Base address for PRQ and TCQ */ + freg_t desc_base; /* Base address of descriptor table */ + u_int filler42[0x45 - 0x42]; + freg_t mode_reg_0; /* Mode register 0 */ + freg_t mode_reg_1; /* Mode register 1 */ + freg_t intr_status_reg;/* Interrupt Status register */ + freg_t mask_reg; /* Mask Register */ + freg_t cell_ctr_high1; /* Total cell transfer count (high) */ + freg_t cell_ctr_lo1; /* Total cell transfer count (low) */ + freg_t state_reg; /* Status register */ + u_int filler4c[0x58 - 0x4c]; + freg_t curr_desc_num; /* Contains the current descriptor num */ + freg_t next_desc; /* Next descriptor */ + freg_t next_vc; /* Next VC */ + u_int filler5b[0x5d - 0x5b]; + freg_t present_slot_cnt;/* Present slot count */ + u_int filler5e[0x6a - 0x5e]; + freg_t new_desc_num; /* New descriptor number */ + freg_t new_vc; /* New VC */ + freg_t sched_tbl_ptr; /* Schedule table pointer */ + freg_t vbrwq_wptr; /* VBR wait queue write pointer */ + freg_t vbrwq_rptr; /* VBR wait queue read pointer */ + freg_t abrwq_wptr; /* ABR wait queue write pointer */ + freg_t abrwq_rptr; /* ABR wait queue read pointer */ + freg_t ubrwq_wptr; /* UBR wait queue write pointer */ + freg_t ubrwq_rptr; /* UBR wait queue read pointer */ + freg_t cbr_vc; /* CBR VC */ + freg_t vbr_sb_vc; /* VBR SB VC */ + freg_t abr_sb_vc; /* ABR SB VC */ + freg_t ubr_sb_vc; /* UBR SB VC */ + freg_t vbr_next_link; /* VBR next link */ + freg_t abr_next_link; /* ABR next link */ + freg_t ubr_next_link; /* UBR next link */ + u_int filler7a[0x7c-0x7a]; + freg_t out_rate_head; /* Out of rate head */ + u_int filler7d[0xca-0x7d]; /* pad out to full address space */ + freg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */ + freg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */ + u_int fillercc[0x100-0xcc]; /* pad out to full address space */ +} ffredn_t; + +typedef struct _rfredn_t { + rreg_t mode_reg_0; /* Mode register 0 */ + rreg_t protocol_id; /* Protocol ID */ + rreg_t mask_reg; /* Mask Register */ + rreg_t intr_status_reg;/* Interrupt status register */ + rreg_t drp_pkt_cntr; /* Dropped packet cntr (clear on read) */ + rreg_t err_cntr; /* Error Counter (cleared on read) */ + u_int filler6[0x08 - 0x06]; + rreg_t raw_base_adr; /* Base addr for raw cell Q */ + u_int filler2[0x0c - 0x09]; + rreg_t cell_ctr0; /* Cell Counter 0 (cleared when read) */ + rreg_t cell_ctr1; /* Cell Counter 1 (cleared when read) */ + u_int filler3[0x0f - 0x0e]; + rreg_t cmd_reg; /* Command register */ + rreg_t desc_base; /* Base address for description table */ + rreg_t vc_lkup_base; /* Base address for VC lookup table */ + rreg_t reass_base; /* Base address for reassembler table */ + rreg_t queue_base; /* Base address for Communication queue */ + u_int filler14[0x16 - 0x14]; + rreg_t pkt_tm_cnt; /* Packet Timeout and count register */ + rreg_t tmout_range; /* Range of reassembley IDs for timeout */ + rreg_t intrvl_cntr; /* Packet aging interval counter */ + rreg_t tmout_indx; /* index of pkt being tested for aging */ + u_int filler1a[0x1c - 0x1a]; + rreg_t vp_lkup_base; /* Base address for VP lookup table */ + rreg_t vp_filter; /* VP filter register */ + rreg_t abr_lkup_base; /* Base address of ABR VC Table */ + u_int filler1f[0x24 - 0x1f]; + rreg_t fdq_st_adr; /* Free desc queue start address */ + rreg_t fdq_ed_adr; /* Free desc queue end address */ + rreg_t fdq_rd_ptr; /* Free desc queue read pointer */ + rreg_t fdq_wr_ptr; /* Free desc queue write pointer */ + rreg_t pcq_st_adr; /* Packet Complete queue start address */ + rreg_t pcq_ed_adr; /* Packet Complete queue end address */ + rreg_t pcq_rd_ptr; /* Packet Complete queue read pointer */ + rreg_t pcq_wr_ptr; /* Packet Complete queue write pointer */ + rreg_t excp_st_adr; /* Exception queue start address */ + rreg_t excp_ed_adr; /* Exception queue end address */ + rreg_t excp_rd_ptr; /* Exception queue read pointer */ + rreg_t excp_wr_ptr; /* Exception queue write pointer */ + u_int filler30[0x34 - 0x30]; + rreg_t raw_st_adr; /* Raw Cell start address */ + rreg_t raw_ed_adr; /* Raw Cell end address */ + rreg_t raw_rd_ptr; /* Raw Cell read pointer */ + rreg_t raw_wr_ptr; /* Raw Cell write pointer */ + rreg_t state_reg; /* State Register */ + u_int filler39[0x42 - 0x39]; + rreg_t buf_size; /* Buffer size */ + u_int filler43; + rreg_t xtra_rm_offset; /* Offset of the additional turnaround RM */ + u_int filler45[0x84 - 0x45]; + rreg_t drp_pkt_cntr_nc;/* Dropped Packet cntr, Not clear on rd */ + rreg_t err_cntr_nc; /* Error Counter, Not clear on read */ + u_int filler86[0x8c - 0x86]; + rreg_t cell_ctr0_nc; /* Cell Counter 0, Not clear on read */ + rreg_t cell_ctr1_nc; /* Cell Counter 1, Not clear on read */ + u_int filler8e[0x100-0x8e]; /* pad out to full address space */ +} rfredn_t; + +typedef struct { + /* Atlantic */ + ffredn_t ffredn; /* F FRED */ + rfredn_t rfredn; /* R FRED */ +} ia_regs_t; + +typedef struct { + u_short f_vc_type; /* VC type */ + u_short f_nrm; /* Nrm */ + u_short f_nrmexp; /* Nrm Exp */ + u_short reserved6; /* */ + u_short f_crm; /* Crm */ + u_short reserved10; /* Reserved */ + u_short reserved12; /* Reserved */ + u_short reserved14; /* Reserved */ + u_short last_cell_slot; /* last_cell_slot_count */ + u_short f_pcr; /* Peak Cell Rate */ + u_short fraction; /* fraction */ + u_short f_icr; /* Initial Cell Rate */ + u_short f_cdf; /* */ + u_short f_mcr; /* Minimum Cell Rate */ + u_short f_acr; /* Allowed Cell Rate */ + u_short f_status; /* */ +} f_vc_abr_entry; + +typedef struct { + u_short r_status_rdf; /* status + RDF */ + u_short r_air; /* AIR */ + u_short reserved4[14]; /* Reserved */ +} r_vc_abr_entry; + +#define MRM 3 +#define MIN(x,y) ((x) < (y)) ? (x) : (y) + +typedef struct srv_cls_param { + u32 class_type; /* CBR/VBR/ABR/UBR; use the enum above */ + u32 pcr; /* Peak Cell Rate (24-bit) */ + /* VBR parameters */ + u32 scr; /* sustainable cell rate */ + u32 max_burst_size; /* ?? cell rate or data rate */ + + /* ABR only UNI 4.0 Parameters */ + u32 mcr; /* Min Cell Rate (24-bit) */ + u32 icr; /* Initial Cell Rate (24-bit) */ + u32 tbe; /* Transient Buffer Exposure (24-bit) */ + u32 frtt; /* Fixed Round Trip Time (24-bit) */ + +#if 0 /* Additional Parameters of TM 4.0 */ +bits 31 30 29 28 27-25 24-22 21-19 18-9 +----------------------------------------------------------------------------- +| NRM present | TRM prsnt | CDF prsnt | ADTF prsnt | NRM | TRM | CDF | ADTF | +----------------------------------------------------------------------------- +#endif /* 0 */ + + u8 nrm; /* Max # of Cells for each forward RM + cell (3-bit) */ + u8 trm; /* Time between forward RM cells (3-bit) */ + u16 adtf; /* ACR Decrease Time Factor (10-bit) */ + u8 cdf; /* Cutoff Decrease Factor (3-bit) */ + u8 rif; /* Rate Increment Factor (4-bit) */ + u8 rdf; /* Rate Decrease Factor (4-bit) */ + u8 reserved; /* 8 bits to keep structure word aligned */ +} srv_cls_param_t; + +struct testTable_t { + u16 lastTime; + u16 fract; + u8 vc_status; +}; + +typedef struct { + u16 vci; + u16 error; +} RX_ERROR_Q; + +typedef struct { + u8 active: 1; + u8 abr: 1; + u8 ubr: 1; + u8 cnt: 5; +#define VC_ACTIVE 0x01 +#define VC_ABR 0x02 +#define VC_UBR 0x04 +} vcstatus_t; + +struct ia_rfL_t { + u32 fdq_st; /* Free desc queue start address */ + u32 fdq_ed; /* Free desc queue end address */ + u32 fdq_rd; /* Free desc queue read pointer */ + u32 fdq_wr; /* Free desc queue write pointer */ + u32 pcq_st; /* Packet Complete queue start address */ + u32 pcq_ed; /* Packet Complete queue end address */ + u32 pcq_rd; /* Packet Complete queue read pointer */ + u32 pcq_wr; /* Packet Complete queue write pointer */ +}; + +struct ia_ffL_t { + u32 prq_st; /* Packet Ready Queue Start Address */ + u32 prq_ed; /* Packet Ready Queue End Address */ + u32 prq_wr; /* Packet Ready Queue write pointer */ + u32 tcq_st; /* Transmit Complete Queue Start Address*/ + u32 tcq_ed; /* Transmit Complete Queue End Address */ + u32 tcq_rd; /* Transmit Complete Queue read pointer */ +}; + +struct desc_tbl_t { + u32 timestamp; + struct ia_vcc *iavcc; + struct sk_buff *txskb; +}; + +typedef struct ia_rtn_q { + struct desc_tbl_t data; + struct ia_rtn_q *next, *tail; +} IARTN_Q; + +#define SUNI_LOSV 0x04 +typedef struct { + u32 suni_master_reset; /* SUNI Master Reset and Identity */ + u32 suni_master_config; /* SUNI Master Configuration */ + u32 suni_master_intr_stat; /* SUNI Master Interrupt Status */ + u32 suni_reserved1; /* Reserved */ + u32 suni_master_clk_monitor;/* SUNI Master Clock Monitor */ + u32 suni_master_control; /* SUNI Master Clock Monitor */ + u32 suni_reserved2[10]; /* Reserved */ + + u32 suni_rsop_control; /* RSOP Control/Interrupt Enable */ + u32 suni_rsop_status; /* RSOP Status/Interrupt States */ + u32 suni_rsop_section_bip8l;/* RSOP Section BIP-8 LSB */ + u32 suni_rsop_section_bip8m;/* RSOP Section BIP-8 MSB */ + + u32 suni_tsop_control; /* TSOP Control */ + u32 suni_tsop_diag; /* TSOP Disgnostics */ + u32 suni_tsop_reserved[2]; /* TSOP Reserved */ + + u32 suni_rlop_cs; /* RLOP Control/Status */ + u32 suni_rlop_intr; /* RLOP Interrupt Enable/Status */ + u32 suni_rlop_line_bip24l; /* RLOP Line BIP-24 LSB */ + u32 suni_rlop_line_bip24; /* RLOP Line BIP-24 */ + u32 suni_rlop_line_bip24m; /* RLOP Line BIP-24 MSB */ + u32 suni_rlop_line_febel; /* RLOP Line FEBE LSB */ + u32 suni_rlop_line_febe; /* RLOP Line FEBE */ + u32 suni_rlop_line_febem; /* RLOP Line FEBE MSB */ + + u32 suni_tlop_control; /* TLOP Control */ + u32 suni_tlop_disg; /* TLOP Disgnostics */ + u32 suni_tlop_reserved[14]; /* TLOP Reserved */ + + u32 suni_rpop_cs; /* RPOP Status/Control */ + u32 suni_rpop_intr; /* RPOP Interrupt/Status */ + u32 suni_rpop_reserved; /* RPOP Reserved */ + u32 suni_rpop_intr_ena; /* RPOP Interrupt Enable */ + u32 suni_rpop_reserved1[3]; /* RPOP Reserved */ + u32 suni_rpop_path_sig; /* RPOP Path Signal Label */ + u32 suni_rpop_bip8l; /* RPOP Path BIP-8 LSB */ + u32 suni_rpop_bip8m; /* RPOP Path BIP-8 MSB */ + u32 suni_rpop_febel; /* RPOP Path FEBE LSB */ + u32 suni_rpop_febem; /* RPOP Path FEBE MSB */ + u32 suni_rpop_reserved2[4]; /* RPOP Reserved */ + + u32 suni_tpop_cntrl_daig; /* TPOP Control/Disgnostics */ + u32 suni_tpop_pointer_ctrl; /* TPOP Pointer Control */ + u32 suni_tpop_sourcer_ctrl; /* TPOP Source Control */ + u32 suni_tpop_reserved1[2]; /* TPOP Reserved */ + u32 suni_tpop_arb_prtl; /* TPOP Arbitrary Pointer LSB */ + u32 suni_tpop_arb_prtm; /* TPOP Arbitrary Pointer MSB */ + u32 suni_tpop_reserved2; /* TPOP Reserved */ + u32 suni_tpop_path_sig; /* TPOP Path Signal Lable */ + u32 suni_tpop_path_status; /* TPOP Path Status */ + u32 suni_tpop_reserved3[6]; /* TPOP Reserved */ + + u32 suni_racp_cs; /* RACP Control/Status */ + u32 suni_racp_intr; /* RACP Interrupt Enable/Status */ + u32 suni_racp_hdr_pattern; /* RACP Match Header Pattern */ + u32 suni_racp_hdr_mask; /* RACP Match Header Mask */ + u32 suni_racp_corr_hcs; /* RACP Correctable HCS Error Count */ + u32 suni_racp_uncorr_hcs; /* RACP Uncorrectable HCS Error Count */ + u32 suni_racp_reserved[10]; /* RACP Reserved */ + + u32 suni_tacp_control; /* TACP Control */ + u32 suni_tacp_idle_hdr_pat; /* TACP Idle Cell Header Pattern */ + u32 suni_tacp_idle_pay_pay; /* TACP Idle Cell Payld Octet Pattern */ + u32 suni_tacp_reserved[5]; /* TACP Reserved */ + + u32 suni_reserved3[24]; /* Reserved */ + + u32 suni_master_test; /* SUNI Master Test */ + u32 suni_reserved_test; /* SUNI Reserved for Test */ +} IA_SUNI; + + +typedef struct _SUNI_STATS_ +{ + u32 valid; // 1 = oc3 PHY card + u32 carrier_detect; // GPIN input + // RSOP: receive section overhead processor + u16 rsop_oof_state; // 1 = out of frame + u16 rsop_lof_state; // 1 = loss of frame + u16 rsop_los_state; // 1 = loss of signal + u32 rsop_los_count; // loss of signal count + u32 rsop_bse_count; // section BIP-8 error count + // RLOP: receive line overhead processor + u16 rlop_ferf_state; // 1 = far end receive failure + u16 rlop_lais_state; // 1 = line AIS + u32 rlop_lbe_count; // BIP-24 count + u32 rlop_febe_count; // FEBE count; + // RPOP: receive path overhead processor + u16 rpop_lop_state; // 1 = LOP + u16 rpop_pais_state; // 1 = path AIS + u16 rpop_pyel_state; // 1 = path yellow alert + u32 rpop_bip_count; // path BIP-8 error count + u32 rpop_febe_count; // path FEBE error count + u16 rpop_psig; // path signal label value + // RACP: receive ATM cell processor + u16 racp_hp_state; // hunt/presync state + u32 racp_fu_count; // FIFO underrun count + u32 racp_fo_count; // FIFO overrun count + u32 racp_chcs_count; // correctable HCS error count + u32 racp_uchcs_count; // uncorrectable HCS error count +} IA_SUNI_STATS; + +typedef struct iadev_t { + /*-----base pointers into (i)chipSAR+ address space */ + u32 *phy; /* base pointer into phy(SUNI) */ + u32 *dma; /* base pointer into DMA control + registers */ + u32 *reg; /* base pointer to SAR registers + - Bus Interface Control Regs */ + u32 *seg_reg; /* base pointer to segmentation engine + internal registers */ + u32 *reass_reg; /* base pointer to reassemble engine + internal registers */ + u32 *ram; /* base pointer to SAR RAM */ + unsigned int seg_ram; + unsigned int reass_ram; + struct dle_q tx_dle_q; + struct free_desc_q *tx_free_desc_qhead; + struct sk_buff_head tx_dma_q, tx_backlog; + spinlock_t tx_lock; + IARTN_Q tx_return_q; + u32 close_pending; +#if LINUX_VERSION_CODE >= 0x20303 + wait_queue_head_t close_wait; + wait_queue_head_t timeout_wait; +#else + struct wait_queue *close_wait; + struct wait_queue *timeout_wait; +#endif + caddr_t *tx_buf; + u16 num_tx_desc, tx_buf_sz, rate_limit; + u32 tx_cell_cnt, tx_pkt_cnt; + u32 MAIN_VC_TABLE_ADDR, EXT_VC_TABLE_ADDR, ABR_SCHED_TABLE_ADDR; + struct dle_q rx_dle_q; + struct free_desc_q *rx_free_desc_qhead; + struct sk_buff_head rx_dma_q; + spinlock_t rx_lock, misc_lock; + struct atm_vcc **rx_open; /* list of all open VCs */ + u16 num_rx_desc, rx_buf_sz, rxing; + u32 rx_pkt_ram, rx_tmp_cnt, rx_tmp_jif; + u32 RX_DESC_BASE_ADDR; + u32 drop_rxpkt, drop_rxcell, rx_cell_cnt, rx_pkt_cnt; + struct atm_dev *next_board; /* other iphase devices */ + struct pci_dev *pci; + int mem; + unsigned long base_diff; /* virtual - real base address */ + unsigned int real_base, base; /* real and virtual base address */ + unsigned int pci_map_size; /*pci map size of board */ + unsigned char irq; + unsigned char bus; + unsigned char dev_fn; + u_short phy_type; + u_short num_vc, memSize, memType; + struct ia_ffL_t ffL; + struct ia_rfL_t rfL; + /* Suni stat */ + // IA_SUNI_STATS suni_stats; + unsigned char carrier_detect; + /* CBR related */ + // transmit DMA & Receive + unsigned int tx_dma_cnt; // number of elements on dma queue + unsigned int rx_dma_cnt; // number of elements on rx dma queue + unsigned int NumEnabledCBR; // number of CBR VCI's enabled. CBR + // receive MARK for Cell FIFO + unsigned int rx_mark_cnt; // number of elements on mark queue + unsigned int CbrTotEntries; // Total CBR Entries in Scheduling Table. + unsigned int CbrRemEntries; // Remaining CBR Entries in Scheduling Table. + unsigned int CbrEntryPt; // CBR Sched Table Entry Point. + unsigned int Granularity; // CBR Granularity given Table Size. + /* ABR related */ + unsigned int sum_mcr, sum_cbr, LineRate; + unsigned int n_abr; + struct desc_tbl_t *desc_tbl; + u_short host_tcq_wr; + struct testTable_t **testTable; +} IADEV; + + +#define INPH_IA_DEV(d) ((IADEV *) (d)->dev_data) +#define INPH_IA_VCC(v) ((struct ia_vcc *) (v)->dev_data) + +/******************* IDT77105 25MB/s PHY DEFINE *****************************/ +typedef struct { + u_int mb25_master_ctrl; /* Master control */ + u_int mb25_intr_status; /* Interrupt status */ + u_int mb25_diag_control; /* Diagnostic control */ + u_int mb25_led_hec; /* LED driver and HEC status/control */ + u_int mb25_low_byte_counter; /* Low byte counter */ + u_int mb25_high_byte_counter; /* High byte counter */ +} ia_mb25_t; + +/* + * Master Control + */ +#define MB25_MC_UPLO 0x80 /* UPLO */ +#define MB25_MC_DREC 0x40 /* Discard receive cell errors */ +#define MB25_MC_ECEIO 0x20 /* Enable Cell Error Interrupts Only */ +#define MB25_MC_TDPC 0x10 /* Transmit data parity check */ +#define MB25_MC_DRIC 0x08 /* Discard receive idle cells */ +#define MB25_MC_HALTTX 0x04 /* Halt Tx */ +#define MB25_MC_UMS 0x02 /* UTOPIA mode select */ +#define MB25_MC_ENABLED 0x01 /* Enable interrupt */ + +/* + * Interrupt Status + */ +#define MB25_IS_GSB 0x40 /* GOOD Symbol Bit */ +#define MB25_IS_HECECR 0x20 /* HEC error cell received */ +#define MB25_IS_SCR 0x10 /* "Short Cell" Received */ +#define MB25_IS_TPE 0x08 /* Trnamsit Parity Error */ +#define MB25_IS_RSCC 0x04 /* Receive Signal Condition change */ +#define MB25_IS_RCSE 0x02 /* Received Cell Symbol Error */ +#define MB25_IS_RFIFOO 0x01 /* Received FIFO Overrun */ + +/* + * Diagnostic Control + */ +#define MB25_DC_FTXCD 0x80 /* Force TxClav deassert */ +#define MB25_DC_RXCOS 0x40 /* RxClav operation select */ +#define MB25_DC_ECEIO 0x20 /* Single/Multi-PHY config select */ +#define MB25_DC_RLFLUSH 0x10 /* Clear receive FIFO */ +#define MB25_DC_IXPE 0x08 /* Insert xmit payload error */ +#define MB25_DC_IXHECE 0x04 /* Insert Xmit HEC Error */ +#define MB25_DC_LB_MASK 0x03 /* Loopback control mask */ + +#define MB25_DC_LL 0x03 /* Line Loopback */ +#define MB25_DC_PL 0x02 /* PHY Loopback */ +#define MB25_DC_NM 0x00 + +#define FE_MASK 0x00F0 +#define FE_MULTI_MODE 0x0000 +#define FE_SINGLE_MODE 0x0010 +#define FE_UTP_OPTION 0x0020 +#define FE_25MBIT_PHY 0x0040 +#define FE_DS3_PHY 0x0080 /* DS3 */ +#define FE_E3_PHY 0x0090 /* E3 */ + +extern void ia_mb25_init (IADEV *); + +/*********************** SUNI_PM7345 PHY DEFINE HERE *********************/ +typedef struct _suni_pm7345_t +{ + u_int suni_config; /* SUNI Configuration */ + u_int suni_intr_enbl; /* SUNI Interrupt Enable */ + u_int suni_intr_stat; /* SUNI Interrupt Status */ + u_int suni_control; /* SUNI Control */ + u_int suni_id_reset; /* SUNI Reset and Identity */ + u_int suni_data_link_ctrl; + u_int suni_rboc_conf_intr_enbl; + u_int suni_rboc_stat; + u_int suni_ds3_frm_cfg; + u_int suni_ds3_frm_intr_enbl; + u_int suni_ds3_frm_intr_stat; + u_int suni_ds3_frm_stat; + u_int suni_rfdl_cfg; + u_int suni_rfdl_enbl_stat; + u_int suni_rfdl_stat; + u_int suni_rfdl_data; + u_int suni_pmon_chng; + u_int suni_pmon_intr_enbl_stat; + u_int suni_reserved1[0x13-0x11]; + u_int suni_pmon_lcv_evt_cnt_lsb; + u_int suni_pmon_lcv_evt_cnt_msb; + u_int suni_pmon_fbe_evt_cnt_lsb; + u_int suni_pmon_fbe_evt_cnt_msb; + u_int suni_pmon_sez_det_cnt_lsb; + u_int suni_pmon_sez_det_cnt_msb; + u_int suni_pmon_pe_evt_cnt_lsb; + u_int suni_pmon_pe_evt_cnt_msb; + u_int suni_pmon_ppe_evt_cnt_lsb; + u_int suni_pmon_ppe_evt_cnt_msb; + u_int suni_pmon_febe_evt_cnt_lsb; + u_int suni_pmon_febe_evt_cnt_msb; + u_int suni_ds3_tran_cfg; + u_int suni_ds3_tran_diag; + u_int suni_reserved2[0x23-0x21]; + u_int suni_xfdl_cfg; + u_int suni_xfdl_intr_st; + u_int suni_xfdl_xmit_data; + u_int suni_xboc_code; + u_int suni_splr_cfg; + u_int suni_splr_intr_en; + u_int suni_splr_intr_st; + u_int suni_splr_status; + u_int suni_splt_cfg; + u_int suni_splt_cntl; + u_int suni_splt_diag_g1; + u_int suni_splt_f1; + u_int suni_cppm_loc_meters; + u_int suni_cppm_chng_of_cppm_perf_meter; + u_int suni_cppm_b1_err_cnt_lsb; + u_int suni_cppm_b1_err_cnt_msb; + u_int suni_cppm_framing_err_cnt_lsb; + u_int suni_cppm_framing_err_cnt_msb; + u_int suni_cppm_febe_cnt_lsb; + u_int suni_cppm_febe_cnt_msb; + u_int suni_cppm_hcs_err_cnt_lsb; + u_int suni_cppm_hcs_err_cnt_msb; + u_int suni_cppm_idle_un_cell_cnt_lsb; + u_int suni_cppm_idle_un_cell_cnt_msb; + u_int suni_cppm_rcv_cell_cnt_lsb; + u_int suni_cppm_rcv_cell_cnt_msb; + u_int suni_cppm_xmit_cell_cnt_lsb; + u_int suni_cppm_xmit_cell_cnt_msb; + u_int suni_rxcp_ctrl; + u_int suni_rxcp_fctrl; + u_int suni_rxcp_intr_en_sts; + u_int suni_rxcp_idle_pat_h1; + u_int suni_rxcp_idle_pat_h2; + u_int suni_rxcp_idle_pat_h3; + u_int suni_rxcp_idle_pat_h4; + u_int suni_rxcp_idle_mask_h1; + u_int suni_rxcp_idle_mask_h2; + u_int suni_rxcp_idle_mask_h3; + u_int suni_rxcp_idle_mask_h4; + u_int suni_rxcp_cell_pat_h1; + u_int suni_rxcp_cell_pat_h2; + u_int suni_rxcp_cell_pat_h3; + u_int suni_rxcp_cell_pat_h4; + u_int suni_rxcp_cell_mask_h1; + u_int suni_rxcp_cell_mask_h2; + u_int suni_rxcp_cell_mask_h3; + u_int suni_rxcp_cell_mask_h4; + u_int suni_rxcp_hcs_cs; + u_int suni_rxcp_lcd_cnt_threshold; + u_int suni_reserved3[0x57-0x54]; + u_int suni_txcp_ctrl; + u_int suni_txcp_intr_en_sts; + u_int suni_txcp_idle_pat_h1; + u_int suni_txcp_idle_pat_h2; + u_int suni_txcp_idle_pat_h3; + u_int suni_txcp_idle_pat_h4; + u_int suni_txcp_idle_pat_h5; + u_int suni_txcp_idle_payload; + u_int suni_e3_frm_fram_options; + u_int suni_e3_frm_maint_options; + u_int suni_e3_frm_fram_intr_enbl; + u_int suni_e3_frm_fram_intr_ind_stat; + u_int suni_e3_frm_maint_intr_enbl; + u_int suni_e3_frm_maint_intr_ind; + u_int suni_e3_frm_maint_stat; + u_int suni_reserved4; + u_int suni_e3_tran_fram_options; + u_int suni_e3_tran_stat_diag_options; + u_int suni_e3_tran_bip_8_err_mask; + u_int suni_e3_tran_maint_adapt_options; + u_int suni_ttb_ctrl; + u_int suni_ttb_trail_trace_id_stat; + u_int suni_ttb_ind_addr; + u_int suni_ttb_ind_data; + u_int suni_ttb_exp_payload_type; + u_int suni_ttb_payload_type_ctrl_stat; + u_int suni_pad5[0x7f-0x71]; + u_int suni_master_test; + u_int suni_pad6[0xff-0x80]; +}suni_pm7345_t; + +#define SUNI_PM7345_T suni_pm7345_t +#define SUNI_PM7345 0x20 /* Suni chip type */ +#define SUNI_PM5346 0x30 /* Suni chip type */ +/* + * SUNI_PM7345 Configuration + */ +#define SUNI_PM7345_CLB 0x01 /* Cell loopback */ +#define SUNI_PM7345_PLB 0x02 /* Payload loopback */ +#define SUNI_PM7345_DLB 0x04 /* Diagnostic loopback */ +#define SUNI_PM7345_LLB 0x80 /* Line loopback */ +#define SUNI_PM7345_E3ENBL 0x40 /* E3 enable bit */ +#define SUNI_PM7345_LOOPT 0x10 /* LOOPT enable bit */ +#define SUNI_PM7345_FIFOBP 0x20 /* FIFO bypass */ +#define SUNI_PM7345_FRMRBP 0x08 /* Framer bypass */ +/* + * DS3 FRMR Interrupt Enable + */ +#define SUNI_DS3_COFAE 0x80 /* Enable change of frame align */ +#define SUNI_DS3_REDE 0x40 /* Enable DS3 RED state intr */ +#define SUNI_DS3_CBITE 0x20 /* Enable Appl ID channel intr */ +#define SUNI_DS3_FERFE 0x10 /* Enable Far End Receive Failure intr*/ +#define SUNI_DS3_IDLE 0x08 /* Enable Idle signal intr */ +#define SUNI_DS3_AISE 0x04 /* Enable Alarm Indication signal intr*/ +#define SUNI_DS3_OOFE 0x02 /* Enable Out of frame intr */ +#define SUNI_DS3_LOSE 0x01 /* Enable Loss of signal intr */ + +/* + * DS3 FRMR Status + */ +#define SUNI_DS3_ACE 0x80 /* Additional Configuration Reg */ +#define SUNI_DS3_REDV 0x40 /* DS3 RED state */ +#define SUNI_DS3_CBITV 0x20 /* Application ID channel state */ +#define SUNI_DS3_FERFV 0x10 /* Far End Receive Failure state*/ +#define SUNI_DS3_IDLV 0x08 /* Idle signal state */ +#define SUNI_DS3_AISV 0x04 /* Alarm Indication signal state*/ +#define SUNI_DS3_OOFV 0x02 /* Out of frame state */ +#define SUNI_DS3_LOSV 0x01 /* Loss of signal state */ + +/* + * E3 FRMR Interrupt/Status + */ +#define SUNI_E3_CZDI 0x40 /* Consecutive Zeros indicator */ +#define SUNI_E3_LOSI 0x20 /* Loss of signal intr status */ +#define SUNI_E3_LCVI 0x10 /* Line code violation intr */ +#define SUNI_E3_COFAI 0x08 /* Change of frame align intr */ +#define SUNI_E3_OOFI 0x04 /* Out of frame intr status */ +#define SUNI_E3_LOS 0x02 /* Loss of signal state */ +#define SUNI_E3_OOF 0x01 /* Out of frame state */ + +/* + * E3 FRMR Maintenance Status + */ +#define SUNI_E3_AISD 0x80 /* Alarm Indication signal state*/ +#define SUNI_E3_FERF_RAI 0x40 /* FERF/RAI indicator */ +#define SUNI_E3_FEBE 0x20 /* Far End Block Error indicator*/ + +/* + * RXCP Control/Status + */ +#define SUNI_DS3_HCSPASS 0x80 /* Pass cell with HEC errors */ +#define SUNI_DS3_HCSDQDB 0x40 /* Control octets in HCS calc */ +#define SUNI_DS3_HCSADD 0x20 /* Add coset poly */ +#define SUNI_DS3_HCK 0x10 /* Control FIFO data path integ chk*/ +#define SUNI_DS3_BLOCK 0x08 /* Enable cell filtering */ +#define SUNI_DS3_DSCR 0x04 /* Disable payload descrambling */ +#define SUNI_DS3_OOCDV 0x02 /* Cell delineation state */ +#define SUNI_DS3_FIFORST 0x01 /* Cell FIFO reset */ + +/* + * RXCP Interrupt Enable/Status + */ +#define SUNI_DS3_OOCDE 0x80 /* Intr enable, change in CDS */ +#define SUNI_DS3_HCSE 0x40 /* Intr enable, corr HCS errors */ +#define SUNI_DS3_FIFOE 0x20 /* Intr enable, unco HCS errors */ +#define SUNI_DS3_OOCDI 0x10 /* SYNC state */ +#define SUNI_DS3_UHCSI 0x08 /* Uncorr. HCS errors detected */ +#define SUNI_DS3_COCAI 0x04 /* Corr. HCS errors detected */ +#define SUNI_DS3_FOVRI 0x02 /* FIFO overrun */ +#define SUNI_DS3_FUDRI 0x01 /* FIFO underrun */ + +extern void ia_suni_pm7345_init (IADEV *iadev); + +///////////////////SUNI_PM7345 PHY DEFINE END ///////////////////////////// + +/* ia_eeprom define*/ +#define MEM_SIZE_MASK 0x000F /* mask of 4 bits defining memory size*/ +#define MEM_SIZE_128K 0x0000 /* board has 128k buffer */ +#define MEM_SIZE_512K 0x0001 /* board has 512K of buffer */ +#define MEM_SIZE_1M 0x0002 /* board has 1M of buffer */ + /* 0x3 to 0xF are reserved for future */ + +#define FE_MASK 0x00F0 /* mask of 4 bits defining FE type */ +#define FE_MULTI_MODE 0x0000 /* 155 MBit multimode fiber */ +#define FE_SINGLE_MODE 0x0010 /* 155 MBit single mode laser */ +#define FE_UTP_OPTION 0x0020 /* 155 MBit UTP front end */ + +#define NOVRAM_SIZE 64 +#define CMD_LEN 10 + +/*********** + * + * Switches and defines for header files. + * + * The following defines are used to turn on and off + * various options in the header files. Primarily useful + * for debugging. + * + ***********/ + +/* + * a list of the commands that can be sent to the NOVRAM + */ + +#define EXTEND 0x100 +#define IAWRITE 0x140 +#define IAREAD 0x180 +#define ERASE 0x1c0 + +#define EWDS 0x00 +#define WRAL 0x10 +#define ERAL 0x20 +#define EWEN 0x30 + +/* + * these bits duplicate the hw_flip.h register settings + * note: how the data in / out bits are defined in the flipper specification + */ + +#define NVCE 0x02 +#define NVSK 0x01 +#define NVDO 0x08 +#define NVDI 0x04 +/*********************** + * + * This define ands the value and the current config register and puts + * the result in the config register + * + ***********************/ + +#define CFG_AND(val) { \ + u32 t; \ + t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); \ + t &= (val); \ + writel(t, iadev->reg+IPHASE5575_EEPROM_ACCESS); \ + } + +/*********************** + * + * This define ors the value and the current config register and puts + * the result in the config register + * + ***********************/ + +#define CFG_OR(val) { \ + u32 t; \ + t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); \ + t |= (val); \ + writel(t, iadev->reg+IPHASE5575_EEPROM_ACCESS); \ + } + +/*********************** + * + * Send a command to the NOVRAM, the command is in cmd. + * + * clear CE and SK. Then assert CE. + * Clock each of the command bits out in the correct order with SK + * exit with CE still asserted + * + ***********************/ + +#define NVRAM_CMD(cmd) { \ + int i; \ + u_short c = cmd; \ + CFG_AND(~(NVCE|NVSK)); \ + CFG_OR(NVCE); \ + for (i=0; ireg+IPHASE5575_EEPROM_ACCESS); \ + value = (_t & NVDO) ? 1 : 0; \ + } + + +#endif /* IPHASE_H */ diff -u --recursive --new-file v2.3.42/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c --- v2.3.42/linux/drivers/atm/nicstar.c Tue Jan 11 22:31:39 2000 +++ linux/drivers/atm/nicstar.c Tue Feb 8 18:23:13 2000 @@ -44,6 +44,9 @@ #ifdef CONFIG_ATM_NICSTAR_USE_SUNI #include "suni.h" #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ +#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 +#include "idt77105.h" +#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ /* Additional code ************************************************************/ @@ -99,8 +102,10 @@ #define NS_DELAY mdelay(1) -#define ALIGN_ADDRESS(addr, alignment) \ +#define ALIGN_BUS_ADDR(addr, alignment) \ ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1)) +#define ALIGN_ADDRESS(addr, alignment) \ + bus_to_virt(ALIGN_BUS_ADDR(virt_to_bus(addr), alignment)) #undef CEIL(d) @@ -164,21 +169,13 @@ static unsigned num_cards = 0; static struct atmdev_ops atm_ops = { - NULL, /* dev_close */ - ns_open, /* open */ - ns_close, /* close */ - ns_ioctl, /* ioctl */ - NULL, /* getsockopt */ - NULL, /* setsockopt */ - ns_send, /* send */ - NULL, /* sg_send */ - NULL, /* send_oam */ - ns_phy_put, /* phy_put */ - ns_phy_get, /* phy_get */ - NULL, /* feedback */ - NULL, /* change_qos */ - NULL, /* free_rx_skb */ - ns_proc_read /* proc_read */ + open: ns_open, + close: ns_close, + ioctl: ns_ioctl, + send: ns_send, + phy_put: ns_phy_put, + phy_get: ns_phy_get, + proc_read: ns_proc_read }; static struct timer_list ns_timer; static char *mac[NS_MAX_CARDS] = { NULL @@ -286,6 +283,12 @@ card = cards[i]; +#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 + if (card->max_pcr == IDT_25_PCR) { + idt77105_stop(card->atmdev); + } +#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ + /* Stop everything */ writel(0x00000000, card->membase + CFG); @@ -457,15 +460,16 @@ cards[i] = card; card->index = i; + card->atmdev = NULL; card->pcidev = pcidev; - card->membase = (u32) pcidev->resource[1].start; + card->membase = pcidev->resource[1].start; #ifdef __powerpc__ /* Compensate for different memory map between host CPU and PCI bus. Shouldn't we use a macro for this? */ card->membase += KERNELBASE; #endif /* __powerpc__ */ - card->membase = (u32) ioremap(card->membase, NS_IOREMAP_SIZE); - if (card->membase == (u32) (NULL)) + card->membase = (unsigned long) ioremap(card->membase, NS_IOREMAP_SIZE); + if (card->membase == 0) { printk("nicstar%d: can't ioremap() membase.\n",i); error = 3; @@ -497,6 +501,7 @@ ns_init_card_error(card, error); return error; } +#ifdef NS_PCI_LATENCY if (pci_latency < NS_PCI_LATENCY) { PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY); @@ -513,6 +518,7 @@ return error; } } +#endif /* NS_PCI_LATENCY */ /* Clear timer overflow */ data = readl(card->membase + STAT); @@ -872,8 +878,8 @@ card->atmdev->ci_range.vpi_bits = card->vpibits; card->atmdev->ci_range.vci_bits = card->vcibits; card->atmdev->link_rate = card->max_pcr; - card->atmdev->phy = NULL; + #ifdef CONFIG_ATM_NICSTAR_USE_SUNI if (card->max_pcr == ATM_OC3_PCR) { suni_init(card->atmdev); @@ -883,6 +889,17 @@ #endif /* MODULE */ } #endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ + +#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 + if (card->max_pcr == IDT_25_PCR) { + idt77105_init(card->atmdev); + /* Note that for the IDT77105 PHY we don't need the awful + * module count hack that the SUNI needs because we can + * stop the '105 when the nicstar module is cleaned up. + */ + } +#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ + if (card->atmdev->phy && card->atmdev->phy->start) card->atmdev->phy->start(card->atmdev); @@ -1798,8 +1815,8 @@ flags = NS_TBD_AAL5; scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data)); scqe.word_3 = cpu_to_le32((u32) skb->len); - scqe.word_4 = cpu_to_le32(((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | - ((u32) vcc->vci) << NS_TBD_VCI_SHIFT); + scqe.word_4 = ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0, + ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? 1 : 0); flags |= NS_TBD_EOPDU; } else /* (vcc->qos.aal == ATM_AAL0) */ @@ -1950,7 +1967,7 @@ { u32 scdi; scq_info *scq; - ns_tsi *previous, *one_ahead, *two_ahead; + ns_tsi *previous = NULL, *one_ahead, *two_ahead; int serviced_entries; /* flag indicating at least on entry was serviced */ serviced_entries = 0; @@ -2679,7 +2696,10 @@ card->intcnt = 0; return retval; } +#if 0 /* Dump 25.6 Mbps PHY registers */ + /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it + here just in case it's needed for debugging. */ if (card->max_pcr == IDT_25_PCR && !left--) { u32 phy_regs[4]; @@ -2696,6 +2716,7 @@ return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n", phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]); } +#endif /* 0 - Dump 25.6 Mbps PHY registers */ #if 0 /* Dump TST */ if (left-- < NS_TST_NUM_ENTRIES) @@ -2757,7 +2778,7 @@ break; default: - return -EINVAL; + return -ENOIOCTLCMD; } if (!copy_to_user((pool_levels *) arg, &pl, sizeof(pl))) @@ -2921,7 +2942,7 @@ else { printk("nicstar%d: %s == NULL \n", card->index, dev->phy ? "dev->phy->ioctl" : "dev->phy"); - return -EINVAL; + return -ENOIOCTLCMD; } } } diff -u --recursive --new-file v2.3.42/linux/drivers/atm/nicstar.h linux/drivers/atm/nicstar.h --- v2.3.42/linux/drivers/atm/nicstar.h Thu Aug 26 13:05:34 1999 +++ linux/drivers/atm/nicstar.h Tue Feb 8 18:23:13 2000 @@ -51,7 +51,7 @@ 128K x 32bit SRAM will limit the maximum VCI. */ -#define NS_PCI_LATENCY 64 /* Must be a multiple of 32 */ +/*#define NS_PCI_LATENCY 64*/ /* Must be a multiple of 32 */ /* Number of buffers initially allocated */ #define NUM_SB 32 /* Must be even */ @@ -240,13 +240,13 @@ #define NS_TBD_VCI_SHIFT 4 #define ns_tbd_mkword_1(flags, m, n, buflen) \ - (cpu_to_le32(flags | m << 23 | n << 16 | buflen)) + (cpu_to_le32((flags) | (m) << 23 | (n) << 16 | (buflen))) #define ns_tbd_mkword_1_novbr(flags, buflen) \ - (cpu_to_le32(flags | buflen | 0x00810000)) + (cpu_to_le32((flags) | (buflen) | 0x00810000)) #define ns_tbd_mkword_3(control, pdulen) \ - (cpu_to_le32(control << 16 | pdulen)) + (cpu_to_le32((control) << 16 | (pdulen))) #define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) \ - (cpu_to_le32(gfc << 28 | vpi << 20 | vci << 4 | pt << 1 | clp))) + (cpu_to_le32((gfc) << 28 | (vpi) << 20 | (vci) << 4 | (pt) << 1 | (clp))) #define NS_TSR_INTENABLE 0x20000000 @@ -455,41 +455,59 @@ /* NISCtAR operation registers ************************************************/ +/* See Section 3.4 of `IDT77211 NICStAR User Manual' from www.idt.com */ + enum ns_regs { - DR0 = 0x00, - DR1 = 0x04, - DR2 = 0x08, - DR3 = 0x0C, - CMD = 0x10, - CFG = 0x14, - STAT = 0x18, - RSQB = 0x1C, - RSQT = 0x20, - RSQH = 0x24, - CDC = 0x28, - VPEC = 0x2C, - ICC = 0x30, - RAWCT = 0x34, - TMR = 0x38, - TSTB = 0x3C, - TSQB = 0x40, - TSQT = 0x44, - TSQH = 0x48, - GP = 0x4C, - VPM = 0x50 + DR0 = 0x00, /* Data Register 0 R/W*/ + DR1 = 0x04, /* Data Register 1 W */ + DR2 = 0x08, /* Data Register 2 W */ + DR3 = 0x0C, /* Data Register 3 W */ + CMD = 0x10, /* Command W */ + CFG = 0x14, /* Configuration R/W */ + STAT = 0x18, /* Status R/W */ + RSQB = 0x1C, /* Receive Status Queue Base W */ + RSQT = 0x20, /* Receive Status Queue Tail R */ + RSQH = 0x24, /* Receive Status Queue Head W */ + CDC = 0x28, /* Cell Drop Counter R/clear */ + VPEC = 0x2C, /* VPI/VCI Lookup Error Count R/clear */ + ICC = 0x30, /* Invalid Cell Count R/clear */ + RAWCT = 0x34, /* Raw Cell Tail R */ + TMR = 0x38, /* Timer R */ + TSTB = 0x3C, /* Transmit Schedule Table Base R/W */ + TSQB = 0x40, /* Transmit Status Queue Base W */ + TSQT = 0x44, /* Transmit Status Queue Tail R */ + TSQH = 0x48, /* Transmit Status Queue Head W */ + GP = 0x4C, /* General Purpose R/W */ + VPM = 0x50 /* VPI/VCI Mask W */ }; /* NICStAR commands issued to the CMD register ********************************/ + +/* Top 4 bits are command opcode, lower 28 are parameters. */ + #define NS_CMD_NO_OPERATION 0x00000000 + /* params always 0 */ + #define NS_CMD_OPENCLOSE_CONNECTION 0x20000000 + /* b19{1=open,0=close} b18-2{SRAM addr} */ + #define NS_CMD_WRITE_SRAM 0x40000000 + /* b18-2{SRAM addr} b1-0{burst size} */ + #define NS_CMD_READ_SRAM 0x50000000 + /* b18-2{SRAM addr} */ + #define NS_CMD_WRITE_FREEBUFQ 0x60000000 + /* b0{large buf indicator} */ + #define NS_CMD_READ_UTILITY 0x80000000 + /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */ + #define NS_CMD_WRITE_UTILITY 0x90000000 + /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */ #define NS_CMD_OPEN_CONNECTION (NS_CMD_OPENCLOSE_CONNECTION | 0x00080000) #define NS_CMD_CLOSE_CONNECTION NS_CMD_OPENCLOSE_CONNECTION @@ -497,28 +515,35 @@ /* NICStAR configuration bits *************************************************/ -#define NS_CFG_SWRST 0x80000000 -#define NS_CFG_RXPATH 0x20000000 -#define NS_CFG_SMBUFSIZE_MASK 0x18000000 -#define NS_CFG_LGBUFSIZE_MASK 0x06000000 -#define NS_CFG_EFBIE 0x01000000 -#define NS_CFG_RSQSIZE_MASK 0x00C00000 -#define NS_CFG_ICACCEPT 0x00200000 -#define NS_CFG_IGNOREGFC 0x00100000 -#define NS_CFG_VPIBITS_MASK 0x000C0000 -#define NS_CFG_RCTSIZE_MASK 0x00030000 -#define NS_CFG_VCERRACCEPT 0x00008000 -#define NS_CFG_RXINT_MASK 0x00007000 -#define NS_CFG_RAWIE 0x00000800 -#define NS_CFG_RSQAFIE 0x00000400 -#define NS_CFG_RXRM 0x00000200 -#define NS_CFG_TMRROIE 0x00000080 -#define NS_CFG_TXEN 0x00000020 -#define NS_CFG_TXIE 0x00000010 -#define NS_CFG_TXURIE 0x00000008 -#define NS_CFG_UMODE 0x00000004 -#define NS_CFG_TSQFIE 0x00000002 -#define NS_CFG_PHYIE 0x00000001 +#define NS_CFG_SWRST 0x80000000 /* Software Reset */ +#define NS_CFG_RXPATH 0x20000000 /* Receive Path Enable */ +#define NS_CFG_SMBUFSIZE_MASK 0x18000000 /* Small Receive Buffer Size */ +#define NS_CFG_LGBUFSIZE_MASK 0x06000000 /* Large Receive Buffer Size */ +#define NS_CFG_EFBIE 0x01000000 /* Empty Free Buffer Queue + Interrupt Enable */ +#define NS_CFG_RSQSIZE_MASK 0x00C00000 /* Receive Status Queue Size */ +#define NS_CFG_ICACCEPT 0x00200000 /* Invalid Cell Accept */ +#define NS_CFG_IGNOREGFC 0x00100000 /* Ignore General Flow Control */ +#define NS_CFG_VPIBITS_MASK 0x000C0000 /* VPI/VCI Bits Size Select */ +#define NS_CFG_RCTSIZE_MASK 0x00030000 /* Receive Connection Table Size */ +#define NS_CFG_VCERRACCEPT 0x00008000 /* VPI/VCI Error Cell Accept */ +#define NS_CFG_RXINT_MASK 0x00007000 /* End of Receive PDU Interrupt + Handling */ +#define NS_CFG_RAWIE 0x00000800 /* Raw Cell Qu' Interrupt Enable */ +#define NS_CFG_RSQAFIE 0x00000400 /* Receive Queue Almost Full + Interrupt Enable */ +#define NS_CFG_RXRM 0x00000200 /* Receive RM Cells */ +#define NS_CFG_TMRROIE 0x00000080 /* Timer Roll Over Interrupt + Enable */ +#define NS_CFG_TXEN 0x00000020 /* Transmit Operation Enable */ +#define NS_CFG_TXIE 0x00000010 /* Transmit Status Interrupt + Enable */ +#define NS_CFG_TXURIE 0x00000008 /* Transmit Under-run Interrupt + Enable */ +#define NS_CFG_UMODE 0x00000004 /* Utopia Mode (cell/byte) Select */ +#define NS_CFG_TSQFIE 0x00000002 /* Transmit Status Queue Full + Interrupt Enable */ +#define NS_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */ #define NS_CFG_SMBUFSIZE_48 0x00000000 #define NS_CFG_SMBUFSIZE_96 0x08000000 @@ -552,22 +577,22 @@ /* NICStAR STATus bits ********************************************************/ -#define NS_STAT_SFBQC_MASK 0xFF000000 -#define NS_STAT_LFBQC_MASK 0x00FF0000 -#define NS_STAT_TSIF 0x00008000 -#define NS_STAT_TXICP 0x00004000 -#define NS_STAT_TSQF 0x00001000 -#define NS_STAT_TMROF 0x00000800 -#define NS_STAT_PHYI 0x00000400 -#define NS_STAT_CMDBZ 0x00000200 -#define NS_STAT_SFBQF 0x00000100 -#define NS_STAT_LFBQF 0x00000080 -#define NS_STAT_RSQF 0x00000040 -#define NS_STAT_EOPDU 0x00000020 -#define NS_STAT_RAWCF 0x00000010 -#define NS_STAT_SFBQE 0x00000008 -#define NS_STAT_LFBQE 0x00000004 -#define NS_STAT_RSQAF 0x00000002 +#define NS_STAT_SFBQC_MASK 0xFF000000 /* hi 8 bits Small Buffer Queue Count */ +#define NS_STAT_LFBQC_MASK 0x00FF0000 /* hi 8 bits Large Buffer Queue Count */ +#define NS_STAT_TSIF 0x00008000 /* Transmit Status Queue Indicator */ +#define NS_STAT_TXICP 0x00004000 /* Transmit Incomplete PDU */ +#define NS_STAT_TSQF 0x00001000 /* Transmit Status Queue Full */ +#define NS_STAT_TMROF 0x00000800 /* Timer Overflow */ +#define NS_STAT_PHYI 0x00000400 /* PHY Device Interrupt */ +#define NS_STAT_CMDBZ 0x00000200 /* Command Busy */ +#define NS_STAT_SFBQF 0x00000100 /* Small Buffer Queue Full */ +#define NS_STAT_LFBQF 0x00000080 /* Large Buffer Queue Full */ +#define NS_STAT_RSQF 0x00000040 /* Receive Status Queue Full */ +#define NS_STAT_EOPDU 0x00000020 /* End of PDU */ +#define NS_STAT_RAWCF 0x00000010 /* Raw Cell Flag */ +#define NS_STAT_SFBQE 0x00000008 /* Small Buffer Queue Empty */ +#define NS_STAT_LFBQE 0x00000004 /* Large Buffer Queue Empty */ +#define NS_STAT_RSQAF 0x00000002 /* Receive Status Queue Almost Full */ #define ns_stat_sfbqc_get(stat) (((stat) & NS_STAT_SFBQC_MASK) >> 23) #define ns_stat_lfbqc_get(stat) (((stat) & NS_STAT_LFBQC_MASK) >> 15) @@ -723,7 +748,7 @@ { int index; /* Card ID to the device driver */ int sram_size; /* In k x 32bit words. 32 or 128 */ - u32 membase; /* Card's memory base address */ + unsigned long membase; /* Card's memory base address */ unsigned long max_pcr; int rct_size; /* Number of entries */ int vpibits; diff -u --recursive --new-file v2.3.42/linux/drivers/atm/suni.c linux/drivers/atm/suni.c --- v2.3.42/linux/drivers/atm/suni.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/atm/suni.c Tue Feb 8 18:23:13 2000 @@ -1,6 +1,6 @@ /* drivers/atm/suni.c - PMC SUNI (PHY) driver */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -181,19 +181,24 @@ case SONET_GETFRSENSE: return -EINVAL; case SUNI_SETLOOP: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if ((int) arg < 0 || (int) arg > SUNI_LM_LOOP) - return -EINVAL; - PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE)) | - ((int) arg == SUNI_LM_DIAG ? SUNI_MCT_DLE : 0) | - ((int) arg == SUNI_LM_LOOP ? SUNI_MCT_LLE : 0),MCT); - PRIV(dev)->loop_mode = (int) arg; - return 0; + { + int int_arg = (int) (long) arg; + + if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (int_arg < 0 || int_arg > SUNI_LM_LOOP) + return -EINVAL; + PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE)) + | (int_arg == SUNI_LM_DIAG ? SUNI_MCT_DLE : + 0) | (int_arg == SUNI_LM_LOOP ? + SUNI_MCT_LLE : 0),MCT); + PRIV(dev)->loop_mode = int_arg; + return 0; + } case SUNI_GETLOOP: return put_user(PRIV(dev)->loop_mode,(int *) arg) ? -EFAULT : 0; default: - return -EINVAL; + return -ENOIOCTLCMD; } } diff -u --recursive --new-file v2.3.42/linux/drivers/atm/uPD98402.c linux/drivers/atm/uPD98402.c --- v2.3.42/linux/drivers/atm/uPD98402.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/atm/uPD98402.c Tue Feb 8 18:23:13 2000 @@ -1,6 +1,6 @@ /* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */ -/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -118,7 +118,7 @@ case SONET_GETFRSENSE: return get_sense(dev,arg); default: - return -EINVAL; + return -ENOIOCTLCMD; } } diff -u --recursive --new-file v2.3.42/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c --- v2.3.42/linux/drivers/atm/zatm.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/atm/zatm.c Tue Feb 8 18:23:13 2000 @@ -1,6 +1,6 @@ /* drivers/atm/zatm.c - ZeitNet ZN122x device driver */ -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ #include @@ -729,9 +729,6 @@ zpokel(zatm_dev,(zpeekl(zatm_dev,pos) & ~(0xffff << shift)) | ((zatm_vcc->rx_chan | uPD98401_RXLT_ENBL) << shift),pos); restore_flags(flags); -/* Ugly hack to ensure that ttcp_atm will work with the current allocation - scheme. @@@ */ -if (vcc->rx_quota < 200000) vcc->rx_quota = 200000; return 0; } @@ -1701,7 +1698,7 @@ } #endif default: - if (!dev->phy->ioctl) return -EINVAL; + if (!dev->phy->ioctl) return -ENOIOCTLCMD; return dev->phy->ioctl(dev,cmd,arg); } } @@ -1710,21 +1707,6 @@ static int zatm_getsockopt(struct atm_vcc *vcc,int level,int optname, void *optval,int optlen) { -#ifdef CONFIG_MMU_HACKS - -static const struct atm_buffconst bctx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; -static const struct atm_buffconst bcrx = { PAGE_SIZE,0,PAGE_SIZE,0,0,0 }; - -#else - -static const struct atm_buffconst bctx = { 4,0,4,0,0,0 }; -static const struct atm_buffconst bcrx = { 4,0,4,0,0,0 }; - -#endif - if (level == SOL_AAL && (optname == SO_BCTXOPT || - optname == SO_BCRXOPT)) - return copy_to_user(optval,optname == SO_BCTXOPT ? &bctx : - &bcrx,sizeof(struct atm_buffconst)) ? -EFAULT : 0; return -EINVAL; } @@ -1797,21 +1779,17 @@ static const struct atmdev_ops ops = { - NULL, /* no dev_close */ - zatm_open, - zatm_close, - zatm_ioctl, - zatm_getsockopt, - zatm_setsockopt, - zatm_send, - NULL /*zatm_sg_send*/, - NULL, /* no send_oam */ - zatm_phy_put, - zatm_phy_get, - zatm_feedback, - zatm_change_qos, - NULL, /* no free_rx_skb */ - NULL /* no proc_read */ + open: zatm_open, + close: zatm_close, + ioctl: zatm_ioctl, + getsockopt: zatm_getsockopt, + setsockopt: zatm_setsockopt, + send: zatm_send, + /*zatm_sg_send*/ + phy_put: zatm_phy_put, + phy_get: zatm_phy_get, + feedback: zatm_feedback, + change_qos: zatm_change_qos, }; diff -u --recursive --new-file v2.3.42/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.42/linux/drivers/block/Config.in Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/Config.in Wed Feb 9 18:48:03 2000 @@ -79,8 +79,8 @@ fi bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then - bool ' HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)' HPT366_FAST_IRQ_PREDICTION - bool ' HPT366 mode three unsupported (EXPERIMENTAL) (WIP)' HPT366_MODE3 + bool ' HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)' CONFIG_HPT366_FAST_IRQ_PREDICTION + bool ' HPT366 mode three unsupported (EXPERIMENTAL) (WIP)' CONFIG_HPT366_MODE3 fi if [ "$CONFIG_X86" = "y" ]; then bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX @@ -106,6 +106,7 @@ if [ "$CONFIG_X86" = "y" ]; then bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 fi + bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 @@ -239,6 +240,7 @@ "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ + "$CONFIG_BLK_DEV_CS5530" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y else diff -u --recursive --new-file v2.3.42/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.3.42/linux/drivers/block/Makefile Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/Makefile Tue Feb 8 11:39:00 2000 @@ -198,6 +198,10 @@ IDE_OBJS += pdc202xx.o endif +ifeq ($(CONFIG_BLK_DEV_CS5530),y) +IDE_OBJS += cs5530.o +endif + ifeq ($(CONFIG_BLK_DEV_PDC4030),y) IDE_OBJS += pdc4030.o endif @@ -350,10 +354,30 @@ endif ifeq ($(CONFIG_MD_RAID5),y) +LX_OBJS += xor.o +CFLAGS_xor.o := $(PROFILING) -fomit-frame-pointer L_OBJS += raid5.o else ifeq ($(CONFIG_MD_RAID5),m) + LX_OBJS += xor.o + CFLAGS_xor.o := $(PROFILING) -fomit-frame-pointer M_OBJS += raid5.o + endif +endif + +ifeq ($(CONFIG_MD_TRANSLUCENT),y) +L_OBJS += translucent.o +else + ifeq ($(CONFIG_MD_TRANSLUCENT),m) + M_OBJS += translucent.o + endif +endif + +ifeq ($(CONFIG_MD_HSM),y) +L_OBJS += hsm.o +else + ifeq ($(CONFIG_MD_HSM),m) + M_OBJS += hsm.o endif endif diff -u --recursive --new-file v2.3.42/linux/drivers/block/acsi_slm.c linux/drivers/block/acsi_slm.c --- v2.3.42/linux/drivers/block/acsi_slm.c Mon Aug 9 12:32:28 1999 +++ linux/drivers/block/acsi_slm.c Wed Feb 9 11:42:35 2000 @@ -271,17 +271,11 @@ static struct timer_list slm_timer = { NULL, NULL, 0, 0, slm_test_ready }; static struct file_operations slm_fops = { - NULL, /* lseek - default */ - slm_read, /* read - status reading */ - slm_write, /* write - printing data write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - slm_ioctl, /* ioctl */ - NULL, /* mmap */ - slm_open, /* open */ - NULL, /* flush */ - slm_release, /* release */ - NULL /* fsync */ + read: slm_read, + write: slm_write, + ioctl: slm_ioctl, + open: slm_open, + release: slm_release, }; diff -u --recursive --new-file v2.3.42/linux/drivers/block/blkpg.c linux/drivers/block/blkpg.c --- v2.3.42/linux/drivers/block/blkpg.c Wed May 26 09:30:31 1999 +++ linux/drivers/block/blkpg.c Tue Feb 8 11:37:29 2000 @@ -65,20 +65,6 @@ return g; } -/* moved here from md.c - will be discarded later */ -char *partition_name (kdev_t dev) { - static char name[40]; /* kdevname returns 32 bytes */ - /* disk_name requires 32 bytes */ - struct gendisk *hd = get_gendisk (dev); - - if (!hd) { - sprintf (name, "[dev %s]", kdevname(dev)); - return (name); - } - - return disk_name (hd, MINOR(dev), name); /* routine in genhd.c */ -} - /* * Add a partition. * diff -u --recursive --new-file v2.3.42/linux/drivers/block/cs5530.c linux/drivers/block/cs5530.c --- v2.3.42/linux/drivers/block/cs5530.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cs5530.c Mon Feb 7 10:00:41 2000 @@ -0,0 +1,420 @@ +/* + * linux/drivers/block/cs5530.c Version 0.2 Jan 30, 2000 + * + * Copyright (C) 2000 Mark Lord + * May be copied or modified under the terms of the GNU General Public License + * + * Development of this chipset driver was funded + * by the nice folks at National Semiconductor. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ide_modes.h" + +/* + * Return the mode name for a drive transfer mode value: + */ +static const char *strmode (byte mode) +{ + switch (mode) { + case XFER_UDMA_4: return("UDMA4"); + case XFER_UDMA_3: return("UDMA3"); + case XFER_UDMA_2: return("UDMA2"); + case XFER_UDMA_1: return("UDMA1"); + case XFER_UDMA_0: return("UDMA0"); + case XFER_MW_DMA_2: return("MDMA2"); + case XFER_MW_DMA_1: return("MDMA1"); + case XFER_MW_DMA_0: return("MDMA0"); + case XFER_SW_DMA_2: return("SDMA2"); + case XFER_SW_DMA_1: return("SDMA1"); + case XFER_SW_DMA_0: return("SDMA0"); + case XFER_PIO_4: return("PIO4"); + case XFER_PIO_3: return("PIO3"); + case XFER_PIO_2: return("PIO2"); + case XFER_PIO_1: return("PIO1"); + case XFER_PIO_0: return("PIO0"); + default: return("???"); + } +} + +/* + * Set a new transfer mode at the drive + */ +int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode) +{ + int i, error = 1; + byte stat; + ide_hwif_t *hwif = HWIF(drive); + + printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, strmode(mode)); + /* + * If this is a DMA mode setting, then turn off all DMA bits. + * We will set one of them back on afterwards, if all goes well. + * + * Not sure why this is needed (it looks very silly), + * but other IDE chipset drivers also do this fiddling. ???? -ml + */ + switch (mode) { + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + case XFER_SW_DMA_2: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + drive->id->dma_ultra &= ~0xFF00; + drive->id->dma_mword &= ~0x0F00; + drive->id->dma_1word &= ~0x0F00; + } + + /* + * Select the drive, and issue the SETFEATURES command + */ + disable_irq(hwif->irq); + udelay(1); + SELECT_DRIVE(HWIF(drive), drive); + udelay(1); + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); + OUT_BYTE(mode, IDE_NSECTOR_REG); + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + udelay(1); /* spec allows drive 400ns to assert "BUSY" */ + + /* + * Wait for drive to become non-BUSY + */ + if ((stat = GET_STAT()) & BUSY_STAT) { + unsigned long flags, timeout; + __save_flags(flags); /* local CPU only */ + ide__sti(); /* local CPU only -- for jiffies */ + timeout = jiffies + WAIT_CMD; + while ((stat = GET_STAT()) & BUSY_STAT) { + if (0 < (signed long)(jiffies - timeout)) + break; + } + __restore_flags(flags); /* local CPU only */ + } + + /* + * Allow status to settle, then read it again. + * A few rare drives vastly violate the 400ns spec here, + * so we'll wait up to 10usec for a "good" status + * rather than expensively fail things immediately. + */ + for (i = 0; i < 10; i++) { + udelay(1); + if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { + error = 0; + break; + } + } + enable_irq(hwif->irq); + + /* + * Turn dma bit on if all is okay + */ + if (error) { + (void) ide_dump_status(drive, "cs5530_set_xfer_mode", stat); + } else { + switch (mode) { + case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; + case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; + case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; + case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break; + case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break; + case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break; + case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break; + case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break; + case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break; + case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break; + case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; + } + } + return error; +} + +/* + * Here are the standard PIO mode 0-4 timings for each "format". + * Format-0 uses fast data reg timings, with slower command reg timings. + * Format-1 uses fast timings for all registers, but won't work with all drives. + */ +static unsigned int cs5530_pio_timings[2][5] = + {{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, + {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}}; + +/* + * After chip reset, the PIO timings are set to 0x0000e132, which is not valid. + */ +#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132) +#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20)) + +/* + * cs5530_tuneproc() handles selection/setting of PIO modes + * for both the chipset and drive. + * + * The ide_init_cs5530() routine guarantees that all drives + * will have valid default PIO timings set up before we get here. + */ +static void cs5530_tuneproc (ide_drive_t *drive, byte pio) /* pio=255 means "autotune" */ +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned int format, basereg = CS5530_BASEREG(hwif); + static byte modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4}; + + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + if (!cs5530_set_xfer_mode(drive, modes[pio])) { + format = (inl(basereg+4) >> 31) & 1; + outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3)); + } +} + +/* + * cs5530_config_dma() handles selection/setting of DMA/UDMA modes + * for both the chipset and drive. + */ +static int cs5530_config_dma (ide_drive_t *drive) +{ + int udma_ok = 1, mode = 0; + ide_hwif_t *hwif = HWIF(drive); + int unit = drive->select.b.unit; + ide_drive_t *mate = &hwif->drives[unit^1]; + struct hd_driveid *id = drive->id; + unsigned int basereg, reg, timings; + + + /* + * Default to DMA-off in case we run into trouble here. + */ + (void)hwif->dmaproc(ide_dma_off_quietly, drive); /* turn off DMA while we fiddle */ + outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */ + + /* + * The CS5530 specifies that two drives sharing a cable cannot + * mix UDMA/MDMA. It has to be one or the other, for the pair, + * though different timings can still be chosen for each drive. + * We could set the appropriate timing bits on the fly, + * but that might be a bit confusing. So, for now we statically + * handle this requirement by looking at our mate drive to see + * what it is capable of, before choosing a mode for our own drive. + */ + if (mate->present) { + struct hd_driveid *mateid = mate->id; + if (mateid && (mateid->capability & 1) && !hwif->dmaproc(ide_dma_bad_drive, mate)) { + if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7)) + udma_ok = 1; + else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7)) + udma_ok = 0; + else + udma_ok = 1; + } + } + + /* + * Now see what the current drive is capable of, + * selecting UDMA only if the mate said it was ok. + */ + if (id && (id->capability & 1) && hwif->autodma && !hwif->dmaproc(ide_dma_bad_drive, drive)) { + if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) { + if (id->dma_ultra & 4) + mode = XFER_UDMA_2; + else if (id->dma_ultra & 2) + mode = XFER_UDMA_1; + else if (id->dma_ultra & 1) + mode = XFER_UDMA_0; + } + if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) { + if (id->dma_mword & 4) + mode = XFER_MW_DMA_2; + else if (id->dma_mword & 2) + mode = XFER_MW_DMA_1; + else if (id->dma_mword & 1) + mode = XFER_MW_DMA_0; + } + } + + /* + * Tell the drive to switch to the new mode; abort on failure. + */ + if (!mode || cs5530_set_xfer_mode(drive, mode)) + return 1; /* failure */ + + /* + * Now tune the chipset to match the drive: + */ + switch (mode) { + case XFER_UDMA_0: timings = 0x00921250; break; + case XFER_UDMA_1: timings = 0x00911140; break; + case XFER_UDMA_2: timings = 0x00911030; break; + case XFER_MW_DMA_0: timings = 0x00077771; break; + case XFER_MW_DMA_1: timings = 0x00012121; break; + case XFER_MW_DMA_2: timings = 0x00002020; break; + default: + printk("%s: cs5530_config_dma: huh? mode=%02x\n", drive->name, mode); + return 1; /* failure */ + } + basereg = CS5530_BASEREG(hwif); + reg = inl(basereg+4); /* get drive0 config register */ + timings |= reg & 0x80000000; /* preserve PIO format bit */ + if (unit == 0) { /* are we configuring drive0? */ + outl(timings, basereg+4); /* write drive0 config register */ + } else { + if (timings & 0x00100000) + reg |= 0x00100000; /* enable UDMA timings for both drives */ + else + reg &= ~0x00100000; /* disable UDMA timings for both drives */ + outl(reg, basereg+4); /* write drive0 config register */ + outl(timings, basereg+12); /* write drive1 config register */ + } + outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */ + + if (!strcmp(drive->name, "hdc")) /* FIXME */ + return 0; + /* + * Finally, turn DMA on in software, and exit. + */ + return hwif->dmaproc(ide_dma_on, drive); /* success */ +} + +/* + * This is a CS5530-specific wrapper for the standard ide_dmaproc(). + * We need it for our custom "ide_dma_check" function. + * All other requests are forwarded to the standard ide_dmaproc(). + */ +int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + switch (func) { + case ide_dma_check: + return cs5530_config_dma(drive); + default: + return ide_dmaproc(func, drive); + } +} + +/* + * Initialize the cs5530 bridge for reliable IDE DMA operation. + */ +unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name) +{ + struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; + unsigned short pcicmd = 0; + unsigned long flags; + + pci_for_each_dev (dev) { + if (dev->vendor == PCI_VENDOR_ID_CYRIX) { + switch (dev->device) { + case PCI_DEVICE_ID_CYRIX_PCI_MASTER: + master_0 = dev; + break; + case PCI_DEVICE_ID_CYRIX_5530_LEGACY: + cs5530_0 = dev; + break; + } + } + } + if (!master_0) { + printk("%s: unable to locate PCI MASTER function\n", name); + return 0; + } + if (!cs5530_0) { + printk("%s: unable to locate CS5530 LEGACY function\n", name); + return 0; + } + + save_flags(flags); + cli(); /* all CPUs (there should only be one CPU with this chipset) */ + + /* + * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530: + * --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530 + */ + pci_read_config_word (cs5530_0, PCI_COMMAND, &pcicmd); + pci_write_config_word(cs5530_0, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); + + /* + * Set PCI CacheLineSize to 16-bytes: + * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530 + */ + pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04); + + /* + * Disable trapping of UDMA register accesses (Win98 hack): + * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530 + */ + pci_write_config_word(cs5530_0, 0xd0, 0x5006); + + /* + * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus: + * The other settings are what is necessary to get the register + * into a sane state for IDE DMA operation. + */ + pci_write_config_byte(master_0, 0x40, 0x1e); + + /* + * Set max PCI burst size (16-bytes seems to work best): + * 16bytes: set bit-1 at 0x41 (reg value of 0x16) + * all others: clear bit-1 at 0x41, and do: + * 128bytes: OR 0x00 at 0x41 + * 256bytes: OR 0x04 at 0x41 + * 512bytes: OR 0x08 at 0x41 + * 1024bytes: OR 0x0c at 0x41 + */ + pci_write_config_byte(master_0, 0x41, 0x14); + + /* + * These settings are necessary to get the chip + * into a sane state for IDE DMA operation. + */ + pci_write_config_byte(master_0, 0x42, 0x00); + pci_write_config_byte(master_0, 0x43, 0xc1); + + restore_flags(flags); + return 0; +} + +/* + * This gets invoked by the IDE driver once for each channel, + * and performs channel-specific pre-initialization before drive probing. + */ +void __init ide_init_cs5530 (ide_hwif_t *hwif) +{ + if (hwif->mate) + hwif->serialized = hwif->mate->serialized = 1; + if (!hwif->dma_base) { + hwif->autodma = 0; + } else { + unsigned int basereg, d0_timings; + + hwif->dmaproc = &cs5530_dmaproc; + hwif->tuneproc = &cs5530_tuneproc; + basereg = CS5530_BASEREG(hwif); + d0_timings = inl(basereg+0); + if (CS5530_BAD_PIO(d0_timings)) { /* PIO timings not initialized? */ + outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0); + if (!hwif->drives[0].autotune) + hwif->drives[0].autotune = 1; /* needs autotuning later */ + } + if (CS5530_BAD_PIO(inl(basereg+8))) { /* PIO timings not initialized? */ + outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8); + if (!hwif->drives[1].autotune) + hwif->drives[1].autotune = 1; /* needs autotuning later */ + } + } +} diff -u --recursive --new-file v2.3.42/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.3.42/linux/drivers/block/floppy.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/floppy.c Wed Feb 9 20:08:09 2000 @@ -289,9 +289,6 @@ #define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x))) -#define INT_OFF save_flags(flags); cli() -#define INT_ON restore_flags(flags) - /* read/write */ #define COMMAND raw_cmd->cmd[0] #define DR_SELECT raw_cmd->cmd[1] @@ -471,7 +468,8 @@ #define FD_COMMAND_ERROR 2 #define FD_COMMAND_OKAY 3 -static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0; +static volatile int command_status = FD_COMMAND_NONE; +static unsigned long fdc_busy = 0; static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); static DECLARE_WAIT_QUEUE_HEAD(command_done); @@ -846,24 +844,36 @@ /* locks the driver */ static int lock_fdc(int drive, int interruptible) { - unsigned long flags; - if (!usage_count){ printk(KERN_ERR "Trying to lock fdc while usage count=0\n"); return -1; } if(floppy_grab_irq_and_dma()==-1) return -EBUSY; - INT_OFF; - while (fdc_busy && NO_SIGNAL) - interruptible_sleep_on(&fdc_wait); - if (fdc_busy){ - INT_ON; - return -EINTR; + + if (test_and_set_bit(0, &fdc_busy)) { + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&fdc_wait, &wait); + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + + if (!test_and_set_bit(0, &fdc_busy)) + break; + + schedule(); + + if (!NO_SIGNAL) { + remove_wait_queue(&fdc_wait, &wait); + return -EINTR; + } + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&fdc_wait, &wait); } - fdc_busy = 1; - INT_ON; command_status = FD_COMMAND_NONE; + reschedule_timeout(drive, "lock fdc", 0); set_fdc(drive); return 0; @@ -886,7 +896,7 @@ command_status = FD_COMMAND_NONE; del_timer(&fd_timeout); cont = NULL; - fdc_busy = 0; + clear_bit(0, &fdc_busy); floppy_release_irq_and_dma(); wake_up(&fdc_wait); } @@ -1031,39 +1041,39 @@ return 0; } +static spinlock_t floppy_hlt_lock = SPIN_LOCK_UNLOCKED; static int hlt_disabled=0; static void floppy_disable_hlt(void) { unsigned long flags; - INT_OFF; - if (!hlt_disabled){ + spin_lock_irqsave(&floppy_hlt_lock, flags); + if (!hlt_disabled) { hlt_disabled=1; #ifdef HAVE_DISABLE_HLT disable_hlt(); #endif } - INT_ON; + spin_unlock_irqrestore(&floppy_hlt_lock, flags); } static void floppy_enable_hlt(void) { unsigned long flags; - INT_OFF; + spin_lock_irqsave(&floppy_hlt_lock, flags); if (hlt_disabled){ hlt_disabled=0; #ifdef HAVE_DISABLE_HLT enable_hlt(); #endif } - INT_ON; + spin_unlock_irqrestore(&floppy_hlt_lock, flags); } static void setup_DMA(void) { - unsigned long flags; unsigned long f; #ifdef FLOPPY_SANITY_CHECK @@ -1085,7 +1095,6 @@ return; } #endif - INT_OFF; f=claim_dma_lock(); fd_disable_dma(); #ifdef fd_dma_setup @@ -1094,7 +1103,6 @@ DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) { release_dma_lock(f); - INT_ON; cont->done(0); FDCS->reset=1; return; @@ -1111,7 +1119,6 @@ fd_enable_dma(); release_dma_lock(f); #endif - INT_ON; floppy_disable_hlt(); } @@ -1759,14 +1766,7 @@ } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2 && max_sensei); } if (handler) { - int cpu = smp_processor_id(); - if(softirq_trylock(cpu)) { - /* got the lock, call the handler immediately */ - handler(); - softirq_endlock(cpu); - } else - /* we interrupted a bottom half. Defer handler */ - schedule_bh( (void *)(void *) handler); + schedule_bh( (void *)(void *) handler); } else FDCS->reset = 1; is_alive("normal interrupt end"); @@ -1854,7 +1854,7 @@ #endif printk("status=%x\n", fd_inb(FD_STATUS)); - printk("fdc_busy=%d\n", fdc_busy); + printk("fdc_busy=%lu\n", fdc_busy); if (DEVICE_INTR) printk("DEVICE_INTR=%p\n", DEVICE_INTR); if (floppy_tq.sync) @@ -2025,25 +2025,36 @@ static int wait_til_done(void (*handler)(void), int interruptible) { int ret; - unsigned long flags; schedule_bh((void *)(void *)handler); - INT_OFF; - while(command_status < 2 && NO_SIGNAL){ - is_alive("wait_til_done"); - if (interruptible) - interruptible_sleep_on(&command_done); - else - sleep_on(&command_done); + + if (command_status < 2 && NO_SIGNAL) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&command_done, &wait); + for (;;) { + set_current_state(interruptible? + TASK_INTERRUPTIBLE: + TASK_UNINTERRUPTIBLE); + + if (command_status >= 2 || !NO_SIGNAL) + break; + + is_alive("wait_til_done"); + + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&command_done, &wait); } + if (command_status < 2){ cancel_activity(); cont = &intr_cont; reset_fdc(); - INT_ON; return -EINTR; } - INT_ON; if (FDCS->reset) command_status = FD_COMMAND_ERROR; @@ -4177,22 +4188,26 @@ return have_no_fdc; } +static spinlock_t floppy_usage_lock = SPIN_LOCK_UNLOCKED; + static int floppy_grab_irq_and_dma(void) { unsigned long flags; - INT_OFF; + spin_lock_irqsave(&floppy_usage_lock, flags); if (usage_count++){ - INT_ON; + spin_unlock_irqrestore(&floppy_usage_lock, flags); return 0; } - INT_ON; + spin_unlock_irqrestore(&floppy_usage_lock, flags); MOD_INC_USE_COUNT; if (fd_request_irq()) { DPRINT("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ); MOD_DEC_USE_COUNT; + spin_lock_irqsave(&floppy_usage_lock, flags); usage_count--; + spin_unlock_irqrestore(&floppy_usage_lock, flags); return -1; } if (fd_request_dma()) { @@ -4200,7 +4215,9 @@ FLOPPY_DMA); fd_free_irq(); MOD_DEC_USE_COUNT; + spin_lock_irqsave(&floppy_usage_lock, flags); usage_count--; + spin_unlock_irqrestore(&floppy_usage_lock, flags); return -1; } @@ -4216,7 +4233,9 @@ release_region(FDCS->address+7, 1); } MOD_DEC_USE_COUNT; + spin_lock_irqsave(&floppy_usage_lock, flags); usage_count--; + spin_unlock_irqrestore(&floppy_usage_lock, flags); return -1; } request_region(FDCS->address, 6, "floppy"); @@ -4258,12 +4277,12 @@ unsigned long tmpaddr; unsigned long flags; - INT_OFF; + spin_lock_irqsave(&floppy_usage_lock, flags); if (--usage_count){ - INT_ON; + spin_unlock_irqrestore(&floppy_usage_lock, flags); return; } - INT_ON; + spin_unlock_irqrestore(&floppy_usage_lock, flags); if(irqdma_allocated) { fd_disable_dma(); diff -u --recursive --new-file v2.3.42/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c --- v2.3.42/linux/drivers/block/hpt366.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/hpt366.c Thu Feb 10 12:37:22 2000 @@ -10,6 +10,7 @@ * development and support. */ +#include #include #include #include @@ -262,20 +263,20 @@ pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h); -#ifdef HPT366_FAST_IRQ_PREDICTION +#ifdef CONFIG_HPT366_FAST_IRQ_PREDICTION /* * Some drives prefer/allow for the method of handling interrupts. */ if (!(reg51h & 0x80)) pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h|0x80); -#else /* ! HPT366_FAST_IRQ_PREDICTION */ +#else /* ! CONFIG_HPT366_FAST_IRQ_PREDICTION */ /* * Disable the "fast interrupt" prediction. * Instead, always wait for the real interrupt from the drive! */ if (reg51h & 0x80) pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80); -#endif /* HPT366_FAST_IRQ_PREDICTION */ +#endif /* CONFIG_HPT366_FAST_IRQ_PREDICTION */ /* * Preserve existing PIO settings: diff -u --recursive --new-file v2.3.42/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.3.42/linux/drivers/block/ide-floppy.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/block/ide-floppy.c Wed Feb 9 19:43:53 2000 @@ -1397,6 +1397,13 @@ *((unsigned short *) &gcw) = id->config; +#ifdef CONFIG_PPC + /* kludge for Apple PowerBook internal zip */ + if ((gcw.device_type == 5) && !strstr(id->model, "CD-ROM") + && strstr(id->model, "ZIP")) + gcw.device_type = 0; +#endif + #if IDEFLOPPY_DEBUG_INFO printk (KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n"); switch (gcw.protocol) { diff -u --recursive --new-file v2.3.42/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c --- v2.3.42/linux/drivers/block/ide-pci.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/ide-pci.c Wed Feb 9 18:48:03 2000 @@ -60,7 +60,7 @@ #define DEVID_ALI15X3 ((ide_pci_devid_t){PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229}) #define DEVID_CY82C693 ((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693}) #define DEVID_HINT ((ide_pci_devid_t){0x3388, 0x8013}) -#define DEVID_CX5530 ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE}) +#define DEVID_CS5530 ((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE}) #define DEVID_AMD7409 ((ide_pci_devid_t){PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409}) #define IDE_IGNORE ((void *)-1) @@ -132,7 +132,15 @@ #define INIT_CY82C693 NULL #endif -#define INIT_CX5530 NULL +#ifdef CONFIG_BLK_DEV_CS5530 +extern unsigned int pci_init_cs5530(struct pci_dev *, const char *); +extern void ide_init_cs5530(ide_hwif_t *); +#define INIT_CS5530 &ide_init_cs5530 +#define PCI_CS5530 &pci_init_cs5530 +#else +#define INIT_CS5530 NULL +#define PCI_CS5530 NULL +#endif #ifdef CONFIG_BLK_DEV_HPT34X extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *); @@ -309,7 +317,7 @@ {DEVID_ALI15X3, "ALI15X3", PCI_ALI15X3, ATA66_ALI15X3, INIT_ALI15X3, DMA_ALI15X3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_CX5530, "CX5530", NULL, NULL, INIT_CX5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, + {DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_AMD7409, "AMD7409", NULL, ATA66_AMD7409, INIT_AMD7409, NULL, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; @@ -614,6 +622,7 @@ IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || #endif /* CONFIG_BLK_DEV_HPT34X */ IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || + IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name); @@ -682,12 +691,12 @@ printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn); if (hpt363_shared_pin && !hpt363_shared_irq) { printk("%s: IDE controller run unsupported mode three!!!\n", d2->name); -#ifndef HPT366_MODE3 +#ifndef CONFIG_HPT366_MODE3 printk("%s: IDE controller report to \n", d->name); return; -#else /* HPT366_MODE3 */ +#else /* CONFIG_HPT366_MODE3 */ printk("%s: OVERRIDE IDE controller not advisable this mode!!!\n", d2->name); -#endif /* HPT366_MODE3 */ +#endif /* CONFIG_HPT366_MODE3 */ } ide_setup_pci_device(dev2, d2); } diff -u --recursive --new-file v2.3.42/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- v2.3.42/linux/drivers/block/ide-pmac.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/ide-pmac.c Wed Feb 9 19:43:53 2000 @@ -14,6 +14,12 @@ * * Copyright (c) 1995-1998 Mark Lord * + * BenH: I began adding more complete timing setup code, mostly because DMA + * won't work on new machines unless timings are setup correctly. This + * code was mainly stolen from Cmd646 driver and should be completed to + * include real timing calc. instead of hard coded values. The format of + * the timing register can be found in Darwin's source code, except for + * Keylargo ATA-4 controller. */ #include #include @@ -36,29 +42,92 @@ #endif #include "ide_modes.h" -int pmac_ide_ports_known; -ide_ioreg_t pmac_ide_regbase[MAX_HWIFS]; -int pmac_ide_irq[MAX_HWIFS]; -int pmac_ide_count; -struct device_node *pmac_ide_node[MAX_HWIFS]; +#undef IDE_PMAC_DEBUG +#define IDE_SYSCLK_NS 30 + +struct pmac_ide_hwif { + ide_ioreg_t regbase; + int irq; + int kind; + struct device_node* node; + u32 timings[2]; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + volatile struct dbdma_regs* dma_regs; + struct dbdma_cmd* dma_table; +#endif + +} pmac_ide[MAX_HWIFS]; + +static int pmac_ide_count; + +enum { + controller_ohare, /* OHare based */ + controller_heathrow, /* Heathrow/Paddington */ + controller_kl_ata3, /* KeyLargo ATA-3 */ + controller_kl_ata4 /* KeyLargo ATA-4 */ +}; + + +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + +typedef struct { + int accessTime; + int cycleTime; +} pmac_ide_timing; + +/* Multiword DMA timings */ +static pmac_ide_timing mdma_timings[] = +{ + { 215, 480 }, /* Mode 0 */ + { 80, 150 }, /* 1 */ + { 70, 120 } /* 2 */ +}; + +/* Ultra DMA timings (for use when I know how to calculate them */ +static pmac_ide_timing udma_timings[] = +{ + { 0, 114 }, /* Mode 0 */ + { 0, 73 }, /* 1 */ + { 0, 54 }, /* 2 */ + { 0, 39 }, /* 3 */ + { 0, 25 } /* 4 */ +}; + #define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */ -static void pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif); +static void pmac_ide_setup_dma(struct device_node *np, int ix); static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive); -static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr); +static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr); +static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio); +static void pmac_ide_selectproc(ide_drive_t *drive); + #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ #ifdef CONFIG_PMAC_PBOOK -static int idepmac_notify(struct pmu_sleep_notifier *self, int when); +static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when); struct pmu_sleep_notifier idepmac_sleep_notifier = { - idepmac_notify, SLEEP_LEVEL_BLOCK, + idepmac_notify_sleep, SLEEP_LEVEL_BLOCK, }; #endif /* CONFIG_PMAC_PBOOK */ +static int +pmac_ide_find(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + ide_ioreg_t base; + int i; + + for (i=0; iio_ports[0]) + return i; + } + return -1; +} + /* - * N.B. this can't be an __init, because the media-bay task can + * N.B. this can't be an initfunc, because the media-bay task can * call ide_[un]register at any time. */ void pmac_ide_init_hwif_ports(hw_regs_t *hw, @@ -71,7 +140,7 @@ return; for (ix = 0; ix < MAX_HWIFS; ++ix) - if (data_port == pmac_ide_regbase[ix]) + if (data_port == pmac_ide[ix].regbase) break; if (ix >= MAX_HWIFS) { @@ -98,27 +167,125 @@ hw->io_ports[8] = data_port + 0x160; if (irq != NULL) - *irq = pmac_ide_irq[ix]; + *irq = pmac_ide[ix].irq; + + ide_hwifs[ix].tuneproc = pmac_ide_tuneproc; + ide_hwifs[ix].selectproc = pmac_ide_selectproc; + if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) { + ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; +#ifdef CONFIG_PMAC_IDEDMA_AUTO + ide_hwifs[ix].autodma = 1; +#endif + } } -void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) +#if 0 +/* This one could be later extended to handle CMD IDE and be used by some kind + * of /proc interface. I want to be able to get the devicetree path of a block + * device for yaboot configuration + */ +struct device_node* +pmac_ide_get_devnode(ide_drive_t *drive) { - ide_pio_data_t d; + int i = pmac_ide_find(drive); + if (i < 0) + return NULL; + return pmac_ide[i].node; +} +#endif - if (_machine != _MACH_Pmac) +/* Setup timings for the selected drive (master/slave). I still need to verify if this + * is enough, I beleive selectproc will be called whenever an IDE command is started, + * but... */ +static void +pmac_ide_selectproc(ide_drive_t *drive) +{ + int i = pmac_ide_find(drive); + if (i < 0) return; + + if (drive->select.all & 0x10) + out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[1]); + else + out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[0]); +} + +/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ +#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) + +static void +pmac_ide_tuneproc(ide_drive_t *drive, byte pio) +{ + ide_pio_data_t d; + int i; + u32 *timings; + int accessTicks, recTicks; + + i = pmac_ide_find(drive); + if (i < 0) + return; + + /* The "ata-4" IDE controller of UMA machines is a bit different. + * We don't do anything for PIO modes until we know how to do the + * calculation. + */ + if (pmac_ide[i].kind == controller_kl_ata4) + return; + pio = ide_get_best_pio_mode(drive, pio, 4, &d); - switch (pio) { - case 4: - out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x211025); - break; - default: - out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x2f8526); - break; + accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time); + if (accessTicks < 4) + accessTicks = 4; + recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4; + if (recTicks < 1) + recTicks = 1; + if (drive->select.all & 0x10) + timings = &pmac_ide[i].timings[1]; + else + timings = &pmac_ide[i].timings[0]; + + *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5); +#ifdef IDE_PMAC_DEBUG + printk("ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n", + pio, *timings); +#endif + + if (drive->select.all == IN_BYTE(IDE_SELECT_REG)) + pmac_ide_selectproc(drive); +} + +ide_ioreg_t +pmac_ide_get_base(int index) +{ + return pmac_ide[index].regbase; +} + +static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; + +kdev_t __init +pmac_find_ide_boot(char *bootdevice, int n) +{ + int i; + + /* + * Look through the list of IDE interfaces for this one. + */ + for (i = 0; i < pmac_ide_count; ++i) { + char *name; + if (!pmac_ide[i].node || !pmac_ide[i].node->full_name) + continue; + name = pmac_ide[i].node->full_name; + if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) { + /* XXX should cope with the 2nd drive as well... */ + return MKDEV(ide_majors[i], 0); + } } + + return 0; } -void __init pmac_ide_probe(void) +void __init +pmac_ide_probe(void) { struct device_node *np; int i; @@ -196,27 +363,70 @@ } else { irq = np->intrs[0].line; } - pmac_ide_regbase[i] = base; - pmac_ide_irq[i] = irq; - pmac_ide_node[i] = np; + pmac_ide[i].regbase = base; + pmac_ide[i].irq = irq; + pmac_ide[i].node = np; + if (device_is_compatible(np, "keylargo-ata")) { + if (strcmp(np->name, "ata-4") == 0) + pmac_ide[i].kind = controller_kl_ata4; + else + pmac_ide[i].kind = controller_kl_ata3; + } else if (device_is_compatible(np, "heathrow-ata")) + pmac_ide[i].kind = controller_heathrow; + else + pmac_ide[i].kind = controller_ohare; if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { media_bay_set_ide_infos(np->parent,base,irq,i); - } else - feature_set(np, FEATURE_IDE_enable); + } else if (pmac_ide[i].kind == controller_ohare) { + /* The code below is having trouble on some ohare machines + * (timing related ?). Until I can put my hand on one of these + * units, I keep the old way + */ + feature_set(np, FEATURE_IDE0_enable); + } else { + /* This is necessary to enable IDE when net-booting */ + int *bidp = (int *)get_property(np, "AAPL,bus-id", NULL); + int bid = bidp ? *bidp : 0; + printk("pmac_ide: enabling IDE bus ID %d\n", bid); + switch(bid) { + case 0: + feature_set(np, FEATURE_IDE0_reset); + feature_set(np, FEATURE_IOBUS_enable); + mdelay(10); + feature_set(np, FEATURE_IDE0_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE0_reset); + break; + case 1: + feature_set(np, FEATURE_Mediabay_IDE_reset); + mdelay(10); + feature_set(np, FEATURE_Mediabay_IDE_enable); + mdelay(10); + feature_clear(np, FEATURE_Mediabay_IDE_reset); + break; + case 2: + /* This one exists only for KL, I don't know about any + enable bit */ + feature_set(np, FEATURE_IDE2_reset); + mdelay(10); + feature_clear(np, FEATURE_IDE2_reset); + break; + } + mdelay(1000); + } hwif = &ide_hwifs[i]; pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->chipset = ide_generic; hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; - hwif->tuneproc = pmac_ide_tuneproc; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC if (np->n_addrs >= 2) { /* has a DBDMA controller channel */ - pmac_ide_setup_dma(np, hwif); + pmac_ide_setup_dma(np, i); } #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ @@ -232,27 +442,28 @@ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC static void __init -pmac_ide_setup_dma(struct device_node *np, ide_hwif_t *hwif) +pmac_ide_setup_dma(struct device_node *np, int ix) { - hwif->dma_base = (unsigned long) ioremap(np->addrs[1].address, 0x200); + pmac_ide[ix].dma_regs = + (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200); /* * Allocate space for the DBDMA commands. * The +2 is +1 for the stop command and +1 to allow for * aligning the start address to a multiple of 16 bytes. */ - hwif->dmatable_cpu = (unsigned long *) + pmac_ide[ix].dma_table = (struct dbdma_cmd*) kmalloc((MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), GFP_KERNEL); - if (hwif->dmatable_cpu == 0) { + if (pmac_ide[ix].dma_table == 0) { printk(KERN_ERR "%s: unable to allocate DMA command list\n", - hwif->name); + ide_hwifs[ix].name); return; } - hwif->dmaproc = &pmac_ide_dmaproc; -#ifdef CONFIG_IDEDMA_PMAC_AUTO - hwif->autodma = 1; -#endif /* CONFIG_IDEDMA_PMAC_AUTO */ + ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; +#ifdef CONFIG_PMAC_IDEDMA_AUTO + ide_hwifs[ix].autodma = 1; +#endif } /* @@ -260,19 +471,19 @@ * for a transfer and sets the DBDMA channel to point to it. */ static int -pmac_ide_build_dmatable(ide_drive_t *drive, int wr) +pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr) { - ide_hwif_t *hwif = HWIF(drive); struct dbdma_cmd *table, *tstart; int count = 0; struct request *rq = HWGROUP(drive)->rq; struct buffer_head *bh = rq->bh; unsigned int size, addr; - volatile struct dbdma_regs *dma - = (volatile struct dbdma_regs *) hwif->dma_base; + volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs; - table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(hwif->dmatable_cpu); + table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table); out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); + while (in_le32(&dma->status) & RUN) + udelay(1); do { /* @@ -335,30 +546,277 @@ return 1; } + +/* This is fun. -DaveM */ +#define IDE_SETXFER 0x03 +#define IDE_SETFEATURE 0xef +#define IDE_DMA2_ENABLE 0x22 +#define IDE_DMA1_ENABLE 0x21 +#define IDE_DMA0_ENABLE 0x20 +#define IDE_UDMA4_ENABLE 0x44 +#define IDE_UDMA3_ENABLE 0x43 +#define IDE_UDMA2_ENABLE 0x42 +#define IDE_UDMA1_ENABLE 0x41 +#define IDE_UDMA0_ENABLE 0x40 + +static __inline__ unsigned char +dma_bits_to_command(unsigned char bits) +{ + if(bits & 0x04) + return IDE_DMA2_ENABLE; + if(bits & 0x02) + return IDE_DMA1_ENABLE; + return IDE_DMA0_ENABLE; +} + +static __inline__ unsigned char +udma_bits_to_command(unsigned char bits) +{ + if(bits & 0x10) + return IDE_UDMA4_ENABLE; + if(bits & 0x08) + return IDE_UDMA3_ENABLE; + if(bits & 0x04) + return IDE_UDMA2_ENABLE; + if(bits & 0x02) + return IDE_UDMA1_ENABLE; + if(bits & 0x01) + return IDE_UDMA0_ENABLE; + return 0; +} + +static __inline__ int +wait_for_ready(ide_drive_t *drive) +{ + /* Timeout bumped for some powerbooks */ + int timeout = 2000; + byte stat; + + while(--timeout) { + stat = GET_STAT(); + if(!(stat & BUSY_STAT)) { + if (drive->ready_stat == 0) + break; + else if((stat & drive->ready_stat) || (stat & ERR_STAT)) + break; + } + mdelay(1); + } + if((stat & ERR_STAT) || timeout <= 0) { + if (stat & ERR_STAT) { + printk("ide_pmace: wait_for_ready, error status: %x\n", stat); + } + return 1; + } + return 0; +} + +static int +pmac_ide_do_setfeature(ide_drive_t *drive, byte command) +{ + unsigned long flags; + byte old_select; + int result = 1; + + save_flags(flags); + cli(); + old_select = IN_BYTE(IDE_SELECT_REG); + OUT_BYTE(drive->select.all, IDE_SELECT_REG); + udelay(10); + OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); + OUT_BYTE(command, IDE_NSECTOR_REG); + if(wait_for_ready(drive)) { + printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); + goto out; + } + OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG); + result = wait_for_ready(drive); + if (result) + printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); +out: + OUT_BYTE(old_select, IDE_SELECT_REG); + restore_flags(flags); + + return result; +} + +static int +pmac_ide_mdma_enable(ide_drive_t *drive, int idx) +{ + byte bits = drive->id->dma_mword & 0x07; + byte feature = dma_bits_to_command(bits); + u32 *timings; + int cycleTime, accessTime; + int accessTicks, recTicks; + struct hd_driveid *id = drive->id; + + /* For now, we don't know these values */ + if (pmac_ide[idx].kind == controller_kl_ata4 && feature != IDE_DMA2_ENABLE) + return 0; + if (pmac_ide[idx].kind != controller_kl_ata4 && feature == IDE_DMA0_ENABLE) + return 0; + + /* Set feature on drive */ + printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf); + if (pmac_ide_do_setfeature(drive, feature)) { + printk("%s: Failed !\n", drive->name); + return 0; + } + + /* which drive is it ? */ + if (drive->select.all & 0x10) + timings = &pmac_ide[idx].timings[1]; + else + timings = &pmac_ide[idx].timings[0]; + + /* Calculate accesstime and cycle time */ + cycleTime = mdma_timings[feature & 0xf].cycleTime; + accessTime = mdma_timings[feature & 0xf].accessTime; + if ((id->field_valid & 2) && (id->eide_dma_time)) + cycleTime = id->eide_dma_time; + if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150)) + cycleTime = 150; + + /* For ata-4 controller, we don't know the calculation */ + if (pmac_ide[idx].kind == controller_kl_ata4) { + *timings = 0x00019465; /* MDMA2 */ + } else { + int halfTick = 0; + int origAccessTime = accessTime; + int origCycleTime = cycleTime; + + accessTicks = SYSCLK_TICKS(accessTime); + if (accessTicks < 1) + accessTicks = 1; + accessTime = accessTicks * IDE_SYSCLK_NS; + recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1; + if (recTicks < 1) + recTicks = 1; + cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS; + + if ((accessTicks > 1) && + ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && + ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) { + halfTick = 1; + accessTicks--; + } + *timings = ((*timings) & 0x7FF) | + (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11; + } +#ifdef IDE_PMAC_DEBUG + printk("ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", + feature & 0xf, *timings); +#endif + return 1; +} + +static int +pmac_ide_udma_enable(ide_drive_t *drive, int idx) +{ + byte bits = drive->id->dma_ultra & 0x1f; + byte feature = udma_bits_to_command(bits); + u32 timings; + + /* We support only those values */ + if (feature != IDE_UDMA4_ENABLE && feature != IDE_UDMA2_ENABLE) + return 0; + + /* Set feature on drive */ + printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); + if (pmac_ide_do_setfeature(drive, feature)) { + printk("%s: Failed !\n", drive->name); + return 0; + } + + /* Put this channel into UDMA mode. + * This value is set by MacOS on the iBook for U/DMA2 + */ + switch(feature) { + case IDE_UDMA4_ENABLE: + timings = 0x0cd00065; + break; + case IDE_UDMA2_ENABLE: + timings = 0x11100065; + break; + } + + if (drive->select.all & 0x10) + pmac_ide[idx].timings[1] = timings; + else + pmac_ide[idx].timings[0] = timings; + + return 1; +} + +static int +pmac_ide_dma_onoff(ide_drive_t *drive, int enable) +{ + int ata4, udma, idx; + struct hd_driveid *id = drive->id; + + drive->using_dma = 0; + + idx = pmac_ide_find(drive); + if (idx < 0) + return 0; + + if (drive->media == ide_floppy) + enable = 0; + if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE)) + enable = 0; + if (check_drive_lists(drive, BAD_DMA_DRIVE)) + enable = 0; + + udma = 0; + ata4 = (pmac_ide[idx].kind == controller_kl_ata4); + + if(enable) { + if (ata4 && (drive->media == ide_disk) && + (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) { + /* UltraDMA modes. */ + drive->using_dma = pmac_ide_udma_enable(drive, idx); + } + if (!drive->using_dma && (id->dma_mword & 0x0007)) { + /* Normal MultiWord DMA modes. */ + drive->using_dma = pmac_ide_mdma_enable(drive, idx); + } + /* Without this, strange things will happen on Keylargo-based + * machines + */ + OUT_BYTE(0, IDE_CONTROL_REG); + if (drive->select.all == IN_BYTE(IDE_SELECT_REG)) + pmac_ide_selectproc(drive); + } + return 0; +} + int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - volatile struct dbdma_regs *dma - = (volatile struct dbdma_regs *) hwif->dma_base; - int dstat; + int ix, dstat; + volatile struct dbdma_regs *dma; + + /* Can we stuff a pointer to our intf structure in config_data + * or select_data in hwif ? + */ + ix = pmac_ide_find(drive); + if (ix < 0) + return 0; + dma = pmac_ide[ix].dma_regs; switch (func) { case ide_dma_on: - /* ide-floppy DMA doesn't work yet... */ - drive->using_dma = drive->media != ide_floppy; - break; case ide_dma_off: - printk(KERN_INFO "%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: - drive->using_dma = 0; + pmac_ide_dma_onoff(drive, (func == ide_dma_on)); break; case ide_dma_check: - /* ide-floppy DMA doesn't work yet... */ - drive->using_dma = hwif->autodma && drive->media != ide_floppy; + if (hwif->autodma) + pmac_ide_dma_onoff(drive, 1); break; case ide_dma_read: case ide_dma_write: - if (!pmac_ide_build_dmatable(drive, func==ide_dma_write)) + if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write)) return 1; drive->waiting_for_dma = 1; if (drive->media != ide_disk) @@ -387,11 +845,9 @@ #ifdef CONFIG_PMAC_PBOOK static void idepmac_sleep_disk(int i, unsigned long base) { + struct device_node* np = pmac_ide[i].node; int j; - /* Reset to PIO 0 */ - out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526); - /* FIXME: We only handle the master IDE */ if (ide_hwifs[i].drives[0].media == ide_disk) { /* Spin down the drive */ @@ -410,23 +866,30 @@ break; } } + feature_set(np, FEATURE_IDE0_reset); + feature_clear(np, FEATURE_IOBUS_enable); + feature_clear(np, FEATURE_IDE0_enable); + pmac_ide[i].timings[0] = 0; + pmac_ide[i].timings[1] = 0; } static void idepmac_wake_disk(int i, unsigned long base) { + struct device_node* np = pmac_ide[i].node; int j; /* Revive IDE disk and controller */ - feature_set(pmac_ide_node[i], FEATURE_IDE_enable); - mdelay(1); - feature_set(pmac_ide_node[i], FEATURE_IDE_DiskPower); - mdelay(100); - feature_set(pmac_ide_node[i], FEATURE_IDE_Reset); - mdelay(1); - /* Make sure we are still PIO0 */ - out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526); + feature_set(np, FEATURE_IOBUS_enable); + mdelay(10); + feature_set(np, FEATURE_IDE0_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE0_reset); mdelay(100); + /* Reset timings */ + pmac_ide_selectproc(&ide_hwifs[i].drives[0]); + mdelay(10); + /* Wait up to 10 seconds (enough for recent drives) */ for (j = 0; j < 100; j++) { int status; @@ -443,14 +906,22 @@ { int timeout; - timeout = 5000; + /* Reset timings */ + pmac_ide_selectproc(&ide_hwifs[i].drives[0]); + mdelay(10); + + timeout = 10000; while ((inb(base + 0x70) & BUSY_STAT) && timeout) { mdelay(1); --timeout; } } -static int idepmac_notify(struct pmu_sleep_notifier *self, int when) +/* Note: We support only master drives for now. This will have to be + * improved if we want to handle sleep on the iMacDV where the CD-ROM + * is a slave + */ +static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) { int i, ret; unsigned long base; @@ -462,10 +933,10 @@ break; case PBOOK_SLEEP_NOW: for (i = 0; i < pmac_ide_count; ++i) { - if ((base = pmac_ide_regbase[i]) == 0) + if ((base = pmac_ide[i].regbase) == 0) continue; /* Disable irq during sleep */ - disable_irq(pmac_ide_irq[i]); + disable_irq(pmac_ide[i].irq); ret = check_media_bay_by_base(base, MB_CD); if (ret == -ENODEV) /* not media bay - put the disk to sleep */ @@ -474,15 +945,22 @@ break; case PBOOK_WAKE: for (i = 0; i < pmac_ide_count; ++i) { - if ((base = pmac_ide_regbase[i]) == 0) + ide_hwif_t *hwif; + if ((base = pmac_ide[i].regbase) == 0) continue; + hwif = &ide_hwifs[i]; /* We don't handle media bay devices this way */ ret = check_media_bay_by_base(base, MB_CD); if (ret == -ENODEV) idepmac_wake_disk(i, base); else if (ret == 0) idepmac_wake_bay(i, base); - enable_irq(pmac_ide_irq[i]); + enable_irq(pmac_ide[i].irq); + +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + if (hwif->drives[0].present && hwif->drives[0].using_dma) + pmac_ide_dma_onoff(&hwif->drives[0], 1); +#endif } break; } diff -u --recursive --new-file v2.3.42/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.3.42/linux/drivers/block/ide-probe.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/ide-probe.c Wed Feb 9 19:43:53 2000 @@ -117,8 +117,16 @@ } type = ide_cdrom; /* Early cdrom models used zero */ case ide_cdrom: - printk ("CDROM"); drive->removable = 1; +#ifdef CONFIG_PPC + /* kludge for Apple PowerBook internal zip */ + if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) { + printk ("FLOPPY"); + type = ide_floppy; + break; + } +#endif + printk ("CDROM"); break; case ide_tape: printk ("TAPE"); diff -u --recursive --new-file v2.3.42/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.3.42/linux/drivers/block/ide-tape.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/ide-tape.c Wed Feb 9 19:47:20 2000 @@ -4372,12 +4372,12 @@ return -ENXIO; } if (tape->onstream && (count != tape->tape_block_size)) { - printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%d used)\n", tape->name, tape->tape_block_size, count); + printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count); return -EINVAL; } #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 3) - printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %d\n", count); + printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count); #endif /* IDETAPE_DEBUG_LOG */ if (tape->chrdev_direction != idetape_direction_read) { @@ -4552,12 +4552,12 @@ return -ENXIO; } if (tape->onstream && (count != tape->tape_block_size)) { - printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%d used)\n", tape->name, tape->tape_block_size, count); + printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count); return -EINVAL; } #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 3) - printk (KERN_INFO "ide-tape: Reached idetape_chrdev_write, count %d\n", count); + printk (KERN_INFO "ide-tape: Reached idetape_chrdev_write, count %Zd\n", count); #endif /* IDETAPE_DEBUG_LOG */ if (tape->chrdev_direction != idetape_direction_write) { /* Initialize write operation */ @@ -5839,18 +5839,11 @@ * Our character device supporting functions, passed to register_chrdev. */ static struct file_operations idetape_fops = { - NULL, /* lseek - default */ - idetape_chrdev_read, /* read */ - idetape_chrdev_write, /* write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - idetape_chrdev_ioctl, /* ioctl */ - NULL, /* mmap */ - idetape_chrdev_open, /* open */ - NULL, /* flush */ - idetape_chrdev_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ + read: idetape_chrdev_read, + write: idetape_chrdev_write, + ioctl: idetape_chrdev_ioctl, + open: idetape_chrdev_open, + release: idetape_chrdev_release, }; /* diff -u --recursive --new-file v2.3.42/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.3.42/linux/drivers/block/ide.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/ide.c Mon Feb 7 19:45:28 2000 @@ -861,7 +861,7 @@ if (drive->media != ide_disk) return; while (i > 0) { - unsigned long buffer[16]; + u32 buffer[16]; unsigned int wcount = (i > 16) ? 16 : i; i -= wcount; ide_input_data (drive, buffer, wcount); diff -u --recursive --new-file v2.3.42/linux/drivers/block/linear.c linux/drivers/block/linear.c --- v2.3.42/linux/drivers/block/linear.c Mon Aug 9 10:23:09 1999 +++ linux/drivers/block/linear.c Tue Feb 8 11:39:00 2000 @@ -1,4 +1,3 @@ - /* linear.c : Multiple Devices driver for Linux Copyright (C) 1994-96 Marc ZYNGIER @@ -19,186 +18,204 @@ #include -#include +#include #include -#include -#include "linear.h" +#include #define MAJOR_NR MD_MAJOR #define MD_DRIVER #define MD_PERSONALITY -static int linear_run (int minor, struct md_dev *mddev) -{ - int cur=0, i, size, dev0_size, nb_zone; - struct linear_data *data; - - MOD_INC_USE_COUNT; - - mddev->private=kmalloc (sizeof (struct linear_data), GFP_KERNEL); - data=(struct linear_data *) mddev->private; - - /* - Find out the smallest device. This was previously done - at registry time, but since it violates modularity, - I moved it here... Any comment ? ;-) - */ - - data->smallest=mddev->devices; - for (i=1; inb_dev; i++) - if (data->smallest->size > mddev->devices[i].size) - data->smallest=mddev->devices+i; - - nb_zone=data->nr_zones= - md_size[minor]/data->smallest->size + - (md_size[minor]%data->smallest->size ? 1 : 0); - - data->hash_table=kmalloc (sizeof (struct linear_hash)*nb_zone, GFP_KERNEL); - - size=mddev->devices[cur].size; - - i=0; - while (curnb_dev) - { - data->hash_table[i].dev0=mddev->devices+cur; - - if (size>=data->smallest->size) /* If we completely fill the slot */ - { - data->hash_table[i++].dev1=NULL; - size-=data->smallest->size; - - if (!size) - { - if (++cur==mddev->nb_dev) continue; - size=mddev->devices[cur].size; - } - - continue; - } - - if (++cur==mddev->nb_dev) /* Last dev, set dev1 as NULL */ - { - data->hash_table[i].dev1=NULL; - continue; - } - - dev0_size=size; /* Here, we use a 2nd dev to fill the slot */ - size=mddev->devices[cur].size; - data->hash_table[i++].dev1=mddev->devices+cur; - size-=(data->smallest->size - dev0_size); - } - - return 0; -} - -static int linear_stop (int minor, struct md_dev *mddev) -{ - struct linear_data *data=(struct linear_data *) mddev->private; - - kfree (data->hash_table); - kfree (data); - - MOD_DEC_USE_COUNT; - - return 0; -} - - -static int linear_map (struct md_dev *mddev, kdev_t *rdev, - unsigned long *rsector, unsigned long size) +static int linear_run (mddev_t *mddev) { - struct linear_data *data=(struct linear_data *) mddev->private; - struct linear_hash *hash; - struct real_dev *tmp_dev; - long block; - - block=*rsector >> 1; - hash=data->hash_table+(block/data->smallest->size); - - if (block >= (hash->dev0->size + hash->dev0->offset)) - { - if (!hash->dev1) - { - printk ("linear_map : hash->dev1==NULL for block %ld\n", block); - return (-1); - } + linear_conf_t *conf; + struct linear_hash *table; + mdk_rdev_t *rdev; + int size, i, j, nb_zone; + unsigned int curr_offset; + + MOD_INC_USE_COUNT; + + conf = kmalloc (sizeof (*conf), GFP_KERNEL); + if (!conf) + goto out; + mddev->private = conf; + + if (md_check_ordering(mddev)) { + printk("linear: disks are not ordered, aborting!\n"); + goto out; + } + /* + * Find the smallest device. + */ + + conf->smallest = NULL; + curr_offset = 0; + ITERATE_RDEV_ORDERED(mddev,rdev,j) { + dev_info_t *disk = conf->disks + j; + + disk->dev = rdev->dev; + disk->size = rdev->size; + disk->offset = curr_offset; + + curr_offset += disk->size; + + if (!conf->smallest || (disk->size < conf->smallest->size)) + conf->smallest = disk; + } + + nb_zone = conf->nr_zones = + md_size[mdidx(mddev)] / conf->smallest->size + + ((md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0); + + conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone, + GFP_KERNEL); + if (!conf->hash_table) + goto out; + + /* + * Here we generate the linear hash table + */ + table = conf->hash_table; + i = 0; + size = 0; + for (j = 0; j < mddev->nb_dev; j++) { + dev_info_t *disk = conf->disks + j; + + if (size < 0) { + table->dev1 = disk; + table++; + } + size += disk->size; + + while (size) { + table->dev0 = disk; + size -= conf->smallest->size; + if (size < 0) + break; + table->dev1 = NULL; + table++; + } + } + table->dev1 = NULL; + + return 0; + +out: + if (conf) + kfree(conf); + MOD_DEC_USE_COUNT; + return 1; +} + +static int linear_stop (mddev_t *mddev) +{ + linear_conf_t *conf = mddev_to_conf(mddev); + + kfree(conf->hash_table); + kfree(conf); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int linear_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) +{ + linear_conf_t *conf = mddev_to_conf(mddev); + struct linear_hash *hash; + dev_info_t *tmp_dev; + long block; + + block = bh->b_blocknr * (bh->b_size >> 10); + hash = conf->hash_table + (block / conf->smallest->size); + + if (block >= (hash->dev0->size + hash->dev0->offset)) { + if (!hash->dev1) { + printk ("linear_make_request : hash->dev1==NULL for block %ld\n", + block); + return -1; + } + tmp_dev = hash->dev1; + } else + tmp_dev = hash->dev0; - tmp_dev=hash->dev1; - } - else - tmp_dev=hash->dev0; - - if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset) - printk ("Block %ld out of bounds on dev %s size %d offset %d\n", - block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); - - *rdev=tmp_dev->dev; - *rsector=(block-(tmp_dev->offset)) << 1; + if (block >= (tmp_dev->size + tmp_dev->offset) + || block < tmp_dev->offset) { + printk ("linear_make_request: Block %ld out of bounds on dev %s size %d offset %d\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); + return -1; + } + bh->b_rdev = tmp_dev->dev; + bh->b_rsector = (block - tmp_dev->offset) << 1; - return (0); + generic_make_request(rw, bh); + return 0; } -static int linear_status (char *page, int minor, struct md_dev *mddev) +static int linear_status (char *page, mddev_t *mddev) { - int sz=0; + int sz = 0; #undef MD_DEBUG #ifdef MD_DEBUG - int j; - struct linear_data *data=(struct linear_data *) mddev->private; + int j; + linear_conf_t *conf = mddev_to_conf(mddev); - sz+=sprintf (page+sz, " "); - for (j=0; jnr_zones; j++) - { - sz+=sprintf (page+sz, "[%s", - partition_name (data->hash_table[j].dev0->dev)); - - if (data->hash_table[j].dev1) - sz+=sprintf (page+sz, "/%s] ", - partition_name(data->hash_table[j].dev1->dev)); - else - sz+=sprintf (page+sz, "] "); - } - - sz+=sprintf (page+sz, "\n"); + sz += sprintf(page+sz, " "); + for (j = 0; j < conf->nr_zones; j++) + { + sz += sprintf(page+sz, "[%s", + partition_name(conf->hash_table[j].dev0->dev)); + + if (conf->hash_table[j].dev1) + sz += sprintf(page+sz, "/%s] ", + partition_name(conf->hash_table[j].dev1->dev)); + else + sz += sprintf(page+sz, "] "); + } + sz += sprintf(page+sz, "\n"); #endif - sz+=sprintf (page+sz, " %dk rounding", 1<param.chunk_size/1024); + return sz; } -static struct md_personality linear_personality= +static mdk_personality_t linear_personality= { - "linear", - linear_map, - NULL, - NULL, - linear_run, - linear_stop, - linear_status, - NULL, /* no ioctls */ - 0 + "linear", + NULL, + linear_make_request, + NULL, + linear_run, + linear_stop, + linear_status, + NULL, + 0, + NULL, + NULL, + NULL, + NULL }; - #ifndef MODULE -void __init linear_init (void) +void md__init linear_init (void) { - register_md_personality (LINEAR, &linear_personality); + register_md_personality (LINEAR, &linear_personality); } #else int init_module (void) { - return (register_md_personality (LINEAR, &linear_personality)); + return (register_md_personality (LINEAR, &linear_personality)); } void cleanup_module (void) { - unregister_md_personality (LINEAR); + unregister_md_personality (LINEAR); } #endif + diff -u --recursive --new-file v2.3.42/linux/drivers/block/linear.h linux/drivers/block/linear.h --- v2.3.42/linux/drivers/block/linear.h Fri Nov 22 06:07:23 1996 +++ linux/drivers/block/linear.h Wed Dec 31 16:00:00 1969 @@ -1,16 +0,0 @@ -#ifndef _LINEAR_H -#define _LINEAR_H - -struct linear_hash -{ - struct real_dev *dev0, *dev1; -}; - -struct linear_data -{ - struct linear_hash *hash_table; /* Dynamically allocated */ - struct real_dev *smallest; - int nr_zones; -}; - -#endif diff -u --recursive --new-file v2.3.42/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.42/linux/drivers/block/ll_rw_blk.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/ll_rw_blk.c Wed Feb 9 19:34:53 2000 @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -65,9 +66,9 @@ */ DECLARE_WAIT_QUEUE_HEAD(wait_for_request); -/* This specifies how many sectors to read ahead on the disk. */ +/* This specifies how many sectors to read ahead on the disk. */ -int read_ahead[MAX_BLKDEV] = {0, }; +int read_ahead[MAX_BLKDEV]; /* blk_dev_struct is: * *request_fn @@ -83,7 +84,7 @@ * * if (!blk_size[MAJOR]) then no minor size checking is done. */ -int * blk_size[MAX_BLKDEV] = { NULL, NULL, }; +int * blk_size[MAX_BLKDEV]; /* * blksize_size contains the size of all block-devices: @@ -92,7 +93,7 @@ * * if (!blksize_size[MAJOR]) then 1024 bytes is assumed. */ -int * blksize_size[MAX_BLKDEV] = { NULL, NULL, }; +int * blksize_size[MAX_BLKDEV]; /* * hardsect_size contains the size of the hardware sector of a device. @@ -106,17 +107,17 @@ * This is currently set by some scsi devices and read by the msdos fs driver. * Other uses may appear later. */ -int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, }; +int * hardsect_size[MAX_BLKDEV]; /* * The following tunes the read-ahead algorithm in mm/filemap.c */ -int * max_readahead[MAX_BLKDEV] = { NULL, NULL, }; +int * max_readahead[MAX_BLKDEV]; /* * Max number of sectors per request */ -int * max_sectors[MAX_BLKDEV] = { NULL, NULL, }; +int * max_sectors[MAX_BLKDEV]; static inline int get_max_sectors(kdev_t dev) { @@ -126,18 +127,24 @@ } /* - * Is called with the request spinlock aquired. * NOTE: the device-specific queue() functions * have to be atomic! */ -static inline request_queue_t *get_queue(kdev_t dev) +request_queue_t * blk_get_queue (kdev_t dev) { int major = MAJOR(dev); struct blk_dev_struct *bdev = blk_dev + major; + unsigned long flags; + request_queue_t *ret; + spin_lock_irqsave(&io_request_lock,flags); if (bdev->queue) - return bdev->queue(dev); - return &blk_dev[major].request_queue; + ret = bdev->queue(dev); + else + ret = &blk_dev[major].request_queue; + spin_unlock_irqrestore(&io_request_lock,flags); + + return ret; } void blk_cleanup_queue(request_queue_t * q) @@ -147,12 +154,17 @@ void blk_queue_headactive(request_queue_t * q, int active) { - q->head_active = active; + q->head_active = active; +} + +void blk_queue_pluggable (request_queue_t * q, plug_device_fn *plug) +{ + q->plug_device_fn = plug; } -void blk_queue_pluggable(request_queue_t * q, int use_plug) +void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) { - q->use_plug = use_plug; + q->make_request_fn = mfn; } static int ll_merge_fn(request_queue_t *q, struct request *req, @@ -185,42 +197,23 @@ void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) { - q->request_fn = rfn; + q->request_fn = rfn; q->current_request = NULL; - q->merge_fn = ll_merge_fn; + q->merge_fn = ll_merge_fn; q->merge_requests_fn = ll_merge_requests_fn; - q->plug_tq.sync = 0; - q->plug_tq.routine = unplug_device; - q->plug_tq.data = q; - q->plugged = 0; + q->make_request_fn = NULL; + q->plug_tq.sync = 0; + q->plug_tq.routine = &generic_unplug_device; + q->plug_tq.data = q; + q->plugged = 0; /* * These booleans describe the queue properties. We set the * default (and most common) values here. Other drivers can * use the appropriate functions to alter the queue properties. * as appropriate. */ - q->use_plug = 1; - q->head_active = 1; -} - -/* - * remove the plug and let it rip.. - */ -void unplug_device(void * data) -{ - request_queue_t * q = (request_queue_t *) data; - unsigned long flags; - - spin_lock_irqsave(&io_request_lock,flags); - if( q->plugged ) - { - q->plugged = 0; - if( q->current_request != NULL ) - { - (q->request_fn)(q); - } - } - spin_unlock_irqrestore(&io_request_lock,flags); + q->plug_device_fn = NULL; + q->head_active = 1; } /* @@ -231,8 +224,12 @@ * This is called with interrupts off and no requests on the queue. * (and with the request spinlock aquired) */ -static inline void plug_device(request_queue_t * q) +inline void generic_plug_device (request_queue_t *q, kdev_t dev) { + if (MAJOR(dev) == MD_MAJOR) { + spin_unlock_irq(&io_request_lock); + BUG(); + } if (q->current_request) return; @@ -241,6 +238,23 @@ } /* + * remove the plug and let it rip.. + */ +void generic_unplug_device(void * data) +{ + request_queue_t * q = (request_queue_t *) data; + unsigned long flags; + + spin_lock_irqsave(&io_request_lock,flags); + if (q->plugged) { + q->plugged = 0; + if (q->current_request) + (q->request_fn)(q); + } + spin_unlock_irqrestore(&io_request_lock,flags); +} + +/* * look for a free request in the first N entries. * NOTE: interrupts must be disabled on the way in (on SMP the request queue * spinlock has to be aquired), and will still be disabled on the way out. @@ -337,7 +351,7 @@ } static inline void drive_stat_acct(struct request *req, - unsigned long nr_sectors, int new_io) + unsigned long nr_sectors, int new_io) { int major = MAJOR(req->rq_dev); int minor = MINOR(req->rq_dev); @@ -384,23 +398,17 @@ * which is important for drive_stat_acct() above. */ -static void add_request(request_queue_t * q, struct request * req) +static inline void __add_request(request_queue_t * q, struct request * req) { int major = MAJOR(req->rq_dev); struct request * tmp; - unsigned long flags; drive_stat_acct(req, req->nr_sectors, 1); req->next = NULL; - /* - * We use the goto to reduce locking complexity - */ - spin_lock_irqsave(&io_request_lock,flags); - if (!(tmp = q->current_request)) { q->current_request = req; - goto out; + return; } for ( ; tmp->next ; tmp = tmp->next) { const int after_current = IN_ORDER(tmp,req); @@ -420,7 +428,7 @@ /* * FIXME(eric) I don't understand why there is a need for this * special case code. It clearly doesn't fit any more with - * the new queueing architecture, and it got added in 2.3.10. + * the new queueing architecture, and it got added in 2.3.10. * I am leaving this in here until I hear back from the COMPAQ * people. */ @@ -433,16 +441,13 @@ { (q->request_fn)(q); } - -out: - spin_unlock_irqrestore(&io_request_lock,flags); } /* * Has to be called with the request spinlock aquired */ static inline void attempt_merge (request_queue_t * q, - struct request *req, + struct request *req, int max_sectors) { struct request *next = req->next; @@ -453,7 +458,6 @@ return; if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors) return; - /* * If we are not allowed to merge these requests, then * return. If we are allowed to merge, then the count @@ -471,11 +475,10 @@ wake_up (&wait_for_request); } -static void __make_request(request_queue_t * q, - int major, - int rw, +static inline void __make_request(request_queue_t * q, int rw, struct buffer_head * bh) { + int major = MAJOR(bh->b_rdev); unsigned int sector, count; struct request * req; int rw_ahead, max_req, max_sectors; @@ -484,28 +487,22 @@ count = bh->b_size >> 9; sector = bh->b_rsector; - /* It had better not be a new buffer by the time we see it */ - if (buffer_new(bh)) - BUG(); - - /* Only one thread can actually submit the I/O. */ - if (test_and_set_bit(BH_Lock, &bh->b_state)) - return; - if (blk_size[major]) { unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; if (maxsector < count || maxsector - count < sector) { bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); - /* This may well happen - the kernel calls bread() - without checking the size of the device, e.g., - when mounting a device. */ + if (!blk_size[major][MINOR(bh->b_rdev)]) + goto end_io; + /* This may well happen - the kernel calls bread() + without checking the size of the device, e.g., + when mounting a device. */ printk(KERN_INFO - "attempt to access beyond end of device\n"); + "attempt to access beyond end of device\n"); printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n", - kdevname(bh->b_rdev), rw, - (sector + count)>>1, - blk_size[major][MINOR(bh->b_rdev)]); + kdevname(bh->b_rdev), rw, + (sector + count)>>1, + blk_size[major][MINOR(bh->b_rdev)]); goto end_io; } } @@ -539,8 +536,7 @@ max_req = (NR_REQUEST * 2) / 3; break; default: - printk(KERN_ERR "make_request: bad block dev cmd," - " must be R/W/RA/WA\n"); + BUG(); goto end_io; } @@ -561,10 +557,12 @@ #endif /* look for a free request. */ - /* Loop uses two requests, 1 for loop and 1 for the real device. - * Cut max_req in half to avoid running out and deadlocking. */ + /* + * Loop uses two requests, 1 for loop and 1 for the real device. + * Cut max_req in half to avoid running out and deadlocking. + */ if ((major == LOOP_MAJOR) || (major == NBD_MAJOR)) - max_req >>= 1; + max_req >>= 1; /* * Try to coalesce the new request with old requests @@ -579,10 +577,10 @@ req = q->current_request; if (!req) { /* MD and loop can't handle plugging without deadlocking */ - if (major != MD_MAJOR && major != LOOP_MAJOR && - major != DDV_MAJOR && major != NBD_MAJOR - && q->use_plug) - plug_device(q); /* is atomic */ + if (q->plug_device_fn) + q->plug_device_fn(q, bh->b_rdev); /* is atomic */ + else + generic_plug_device(q, bh->b_rdev); /* is atomic */ goto get_rq; } @@ -667,13 +665,34 @@ get_rq: req = get_request(max_req, bh->b_rdev); - spin_unlock_irqrestore(&io_request_lock,flags); - -/* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */ + /* + * if no request available: if rw_ahead, forget it, + * otherwise try again blocking.. + */ if (!req) { + spin_unlock_irqrestore(&io_request_lock,flags); if (rw_ahead) goto end_io; req = __get_request_wait(max_req, bh->b_rdev); + spin_lock_irqsave(&io_request_lock,flags); + } + /* + * Dont start the IO if the buffer has been + * invalidated meanwhile. (we have to do this + * within the io request lock and atomically + * before adding the request, see buffer.c's + * insert_into_queues_exclusive() function. + */ + if (!test_bit(BH_Req, &bh->b_state)) { + req->rq_status = RQ_INACTIVE; + spin_unlock_irqrestore(&io_request_lock,flags); + /* + * A fake 'everything went ok' completion event. + * The bh doesnt matter anymore, but we should not + * signal errors to RAID levels. + */ + bh->b_end_io(bh, 1); + return; } /* fill up the request-info, and add it to the queue */ @@ -689,52 +708,51 @@ req->bh = bh; req->bhtail = bh; req->next = NULL; - add_request(q, req); + __add_request(q, req); + spin_unlock_irqrestore(&io_request_lock, flags); return; end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } -void make_request(int major,int rw, struct buffer_head * bh) +void generic_make_request(int rw, struct buffer_head * bh) { request_queue_t * q; unsigned long flags; - - q = get_queue(bh->b_dev); - __make_request(q, major, rw, bh); + q = blk_get_queue(bh->b_rdev); + + __make_request(q, rw, bh); spin_lock_irqsave(&io_request_lock,flags); - if( !q->plugged ) + if (q && !q->plugged) (q->request_fn)(q); spin_unlock_irqrestore(&io_request_lock,flags); } - /* This function can be used to request a number of buffers from a block device. Currently the only restriction is that all buffers must belong to the same device */ -void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) +static void __ll_rw_block(int rw, int nr, struct buffer_head * bh[],int haslock) { unsigned int major; int correct_size; - request_queue_t * q; - unsigned long flags; + request_queue_t *q; int i; - major = MAJOR(bh[0]->b_dev); - if (!(q = get_queue(bh[0]->b_dev))) { + q = blk_get_queue(bh[0]->b_dev); + if (!q) { printk(KERN_ERR "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n", kdevname(bh[0]->b_dev), bh[0]->b_blocknr); goto sorry; } - /* Determine correct block size for this device. */ + /* Determine correct block size for this device. */ correct_size = BLOCK_SIZE; if (blksize_size[major]) { i = blksize_size[major][MINOR(bh[0]->b_dev)]; @@ -742,7 +760,7 @@ correct_size = i; } - /* Verify requested block sizes. */ + /* Verify requested block sizes. */ for (i = 0; i < nr; i++) { if (bh[i]->b_size != correct_size) { printk(KERN_NOTICE "ll_rw_block: device %s: " @@ -751,19 +769,6 @@ correct_size, bh[i]->b_size); goto sorry; } - - /* Md remaps blocks now */ - bh[i]->b_rdev = bh[i]->b_dev; - bh[i]->b_rsector=bh[i]->b_blocknr*(bh[i]->b_size >> 9); -#ifdef CONFIG_BLK_DEV_MD - if (major==MD_MAJOR && - md_map (MINOR(bh[i]->b_dev), &bh[i]->b_rdev, - &bh[i]->b_rsector, bh[i]->b_size >> 9)) { - printk (KERN_ERR - "Bad md_map in ll_rw_block\n"); - goto sorry; - } -#endif } if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) { @@ -773,25 +778,29 @@ } for (i = 0; i < nr; i++) { + /* Only one thread can actually submit the I/O. */ + if (haslock) { + if (!buffer_locked(bh[i])) + BUG(); + } else { + if (test_and_set_bit(BH_Lock, &bh[i]->b_state)) + continue; + } set_bit(BH_Req, &bh[i]->b_state); -#ifdef CONFIG_BLK_DEV_MD - if (MAJOR(bh[i]->b_dev) == MD_MAJOR) { - md_make_request(MINOR (bh[i]->b_dev), rw, bh[i]); - continue; + + if (q->make_request_fn) + q->make_request_fn(rw, bh[i]); + else { + bh[i]->b_rdev = bh[i]->b_dev; + bh[i]->b_rsector = bh[i]->b_blocknr*(bh[i]->b_size>>9); + + generic_make_request(rw, bh[i]); } -#endif - __make_request(q, MAJOR(bh[i]->b_rdev), rw, bh[i]); } - spin_lock_irqsave(&io_request_lock,flags); - if( !q->plugged ) - { - (q->request_fn)(q); - } - spin_unlock_irqrestore(&io_request_lock,flags); return; - sorry: +sorry: for (i = 0; i < nr; i++) { mark_buffer_clean(bh[i]); /* remeber to refile it */ clear_bit(BH_Uptodate, &bh[i]->b_state); @@ -800,8 +809,18 @@ return; } +void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) +{ + __ll_rw_block(rw, nr, bh, 0); +} + +void ll_rw_block_locked(int rw, int nr, struct buffer_head * bh[]) +{ + __ll_rw_block(rw, nr, bh, 1); +} + #ifdef CONFIG_STRAM_SWAP -extern int stram_device_init( void ); +extern int stram_device_init (void); #endif /* @@ -811,8 +830,7 @@ * 1 means we are done */ -int -end_that_request_first( struct request *req, int uptodate, char *name ) +int end_that_request_first (struct request *req, int uptodate, char *name) { struct buffer_head * bh; int nsect; @@ -847,8 +865,7 @@ return 0; } -void -end_that_request_last( struct request *req ) +void end_that_request_last(struct request *req) { if (req->sem != NULL) up(req->sem); @@ -862,7 +879,7 @@ struct blk_dev_struct *dev; for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;) { - dev->queue = NULL; + dev->queue = NULL; blk_init_queue(&dev->request_queue, NULL); } @@ -923,8 +940,8 @@ floppy_init(); #else #if !defined (__mc68000__) && !defined(CONFIG_PPC) && !defined(__sparc__)\ - && !defined(CONFIG_APUS) && !defined(__sh__) - outb_p(0xc, 0x3f2); + && !defined(CONFIG_APUS) && !defined(__sh__) && !defined(__ia64__) + outb_p(0xc, 0x3f2); /* XXX do something with the floppy controller?? */ #endif #endif #ifdef CONFIG_CDU31A @@ -943,7 +960,7 @@ sbpcd_init(); #endif CONFIG_SBPCD #ifdef CONFIG_AZTCD - aztcd_init(); + aztcd_init(); #endif CONFIG_AZTCD #ifdef CONFIG_CDU535 sony535_init(); @@ -981,3 +998,5 @@ EXPORT_SYMBOL(blk_init_queue); EXPORT_SYMBOL(blk_cleanup_queue); EXPORT_SYMBOL(blk_queue_headactive); +EXPORT_SYMBOL(blk_queue_pluggable); +EXPORT_SYMBOL(generic_make_request); diff -u --recursive --new-file v2.3.42/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.3.42/linux/drivers/block/loop.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/loop.c Thu Feb 10 12:16:57 2000 @@ -342,8 +342,8 @@ set_fs(old_fs); if (retval < 0) { - printk(KERN_WARNING "loop: cannot create block - FS write failed: code %d\n", - retval); + printk(KERN_WARNING "loop: cannot create block - FS write failed: code %Zi\n", + retval); return FALSE; } else { return TRUE; @@ -386,7 +386,11 @@ a file structure */ lo->lo_backing_file = NULL; } else if (S_ISREG(inode->i_mode)) { - if (!inode->i_op->get_block) { + /* + * Total crap. We should just use pagecache instead of trying + * to redirect on block level. + */ + if (!inode->i_mapping->a_ops->bmap) { printk(KERN_ERR "loop: device has no block access/not implemented\n"); goto out_putf; } diff -u --recursive --new-file v2.3.42/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.3.42/linux/drivers/block/md.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/md.c Tue Feb 8 18:44:57 2000 @@ -1,21 +1,17 @@ - /* md.c : Multiple Devices driver for Linux - Copyright (C) 1994-96 Marc ZYNGIER - or - + Copyright (C) 1998, 1999, 2000 Ingo Molnar - A lot of inspiration came from hd.c ... + completely rewritten, based on the MD driver code from Marc Zyngier - kerneld support by Boris Tobotras - boot support for linear and striped mode by Harald Hoyer + Changes: - RAID-1/RAID-5 extensions by: - Ingo Molnar, Miguel de Icaza, Gadi Oxman + - RAID-1/RAID-5 extensions by Miguel de Icaza, Gadi Oxman, Ingo Molnar + - boot support for linear and striped mode by Harald Hoyer + - kerneld support by Boris Tobotras + - kmod support by: Cyrus Durgin + - RAID0 bugfixes: Mark Anthony Lisher - Changes for kmod by: - Cyrus Durgin - 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, or (at your option) @@ -26,731 +22,2857 @@ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* - * Current RAID-1,4,5 parallel reconstruction speed limit is 1024 KB/sec, so - * the extra system load does not show up that much. Increase it if your - * system can take more. - */ -#define SPEED_LIMIT 1024 - #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + #ifdef CONFIG_KMOD #include #endif -#include -#include #define __KERNEL_SYSCALLS__ #include +#include + +extern asmlinkage int sys_sched_yield(void); +extern asmlinkage int sys_setsid(void); + +extern unsigned long io_events[MAX_BLKDEV]; + #define MAJOR_NR MD_MAJOR #define MD_DRIVER #include -#include -#include -#include -#include #ifdef CONFIG_MD_BOOT -extern kdev_t name_to_kdev_t(char *line) __init; +extern kdev_t name_to_kdev_t(char *line) md__init; +#endif + +#define DEBUG 0 +#if DEBUG +# define dprintk(x...) printk(x) +#else +# define dprintk(x...) do { } while(0) #endif -static struct hd_struct md_hd_struct[MAX_MD_DEV]; -static int md_blocksizes[MAX_MD_DEV]; -int md_maxreadahead[MAX_MD_DEV]; -#if SUPPORT_RECONSTRUCTION -static struct md_thread *md_sync_thread = NULL; -#endif /* SUPPORT_RECONSTRUCTION */ +static mdk_personality_t *pers[MAX_PERSONALITY] = {NULL, }; -int md_size[MAX_MD_DEV]={0, }; +/* + * these have to be allocated separately because external + * subsystems want to have a pre-defined structure + */ +struct hd_struct md_hd_struct[MAX_MD_DEVS]; +static int md_blocksizes[MAX_MD_DEVS]; +static int md_maxreadahead[MAX_MD_DEVS]; +static mdk_thread_t *md_recovery_thread = NULL; + +int md_size[MAX_MD_DEVS] = {0, }; static struct gendisk md_gendisk= { - MD_MAJOR, - "md", - 0, - 1, - md_hd_struct, - md_size, - MAX_MD_DEV, - NULL, - NULL + MD_MAJOR, + "md", + 0, + 1, + md_hd_struct, + md_size, + MAX_MD_DEVS, + NULL, + NULL }; -static struct md_personality *pers[MAX_PERSONALITY]={NULL, }; -struct md_dev md_dev[MAX_MD_DEV]; +void md_plug_device (request_queue_t *mdqueue, kdev_t dev) +{ + mdk_rdev_t * rdev; + struct md_list_head *tmp; + request_queue_t *q; + mddev_t *mddev; -int md_thread(void * arg); + if (!md_test_and_set_bit(0, (atomic_t *)&mdqueue->plugged)) { + mddev = kdev_to_mddev(dev); + ITERATE_RDEV(mddev,rdev,tmp) { + q = blk_get_queue(rdev->dev); + generic_unplug_device(q); + } + queue_task(&mdqueue->plug_tq, &tq_disk); + } +} -static int legacy_raid_sb (int minor, int pnum) +static void md_unplug_device (void * data) { - int i, factor; + mdk_rdev_t * rdev; + struct md_list_head *tmp; + mddev_t *mddev = (mddev_t *)data; + request_queue_t *mdqueue = &mddev->queue, *q; - factor = 1 << FACTOR_SHIFT(FACTOR((md_dev+minor))); + clear_bit(0, (atomic_t *)&mdqueue->plugged); + ITERATE_RDEV(mddev,rdev,tmp) { + q = blk_get_queue(rdev->dev); + generic_unplug_device(q); + } +} - /***** - * do size and offset calculations. - */ - for (i=0; i> PERSONALITY_SHIFT) - md_maxreadahead[minor] = MD_DEFAULT_DISK_READAHEAD * md_dev[minor].nb_dev; - return 0; + if (mddev_map[minor].mddev != NULL) { + MD_BUG(); + return; + } + mddev_map[minor].mddev = mddev; + mddev_map[minor].data = data; } -static void free_sb (struct md_dev *mddev) +void del_mddev_mapping (mddev_t * mddev, kdev_t dev) { - int i; - struct real_dev *realdev; + unsigned int minor = MINOR(dev); - if (mddev->sb) { - free_page((unsigned long) mddev->sb); - mddev->sb = NULL; + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return; } - for (i = 0; i nb_dev; i++) { - realdev = mddev->devices + i; - if (realdev->sb) { - free_page((unsigned long) realdev->sb); - realdev->sb = NULL; - } + if (mddev_map[minor].mddev != mddev) { + MD_BUG(); + return; } + mddev_map[minor].mddev = NULL; + mddev_map[minor].data = NULL; } -/* - * Check one RAID superblock for generic plausibility - */ +static request_queue_t *md_get_queue (kdev_t dev) +{ + mddev_t *mddev = kdev_to_mddev(dev); -#define BAD_MAGIC KERN_ERR \ -"md: %s: invalid raid superblock magic (%x) on block %u\n" + if (!mddev) + return NULL; + return &mddev->queue; +} -#define OUT_OF_MEM KERN_ALERT \ -"md: out of memory.\n" +static void do_md_request (request_queue_t * q) +{ + printk(KERN_ALERT "Got md request, not good..."); + BUG(); + return; +} -#define NO_DEVICE KERN_ERR \ -"md: disabled device %s\n" +void md_make_request (int rw, struct buffer_head * bh) +{ + mddev_t *mddev = kdev_to_mddev(bh->b_dev); -#define SUCCESS 0 -#define FAILURE -1 + if (!mddev || !mddev->pers) + bh->b_end_io(bh, 0); + else { + if ((rw == READ || rw == READA) && buffer_uptodate(bh)) + bh->b_end_io(bh, 1); + else + mddev->pers->make_request(mddev, rw, bh); + } +} -static int analyze_one_sb (struct real_dev * rdev) +static mddev_t * alloc_mddev (kdev_t dev) { - int ret = FAILURE; - struct buffer_head *bh; - kdev_t dev = rdev->dev; - md_superblock_t *sb; + request_queue_t *q; + mddev_t *mddev; + + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return 0; + } + mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL); + if (!mddev) + return NULL; + + memset(mddev, 0, sizeof(*mddev)); + + mddev->__minor = MINOR(dev); + init_MUTEX(&mddev->reconfig_sem); + init_MUTEX(&mddev->recovery_sem); + init_MUTEX(&mddev->resync_sem); + MD_INIT_LIST_HEAD(&mddev->disks); + MD_INIT_LIST_HEAD(&mddev->all_mddevs); + + q = &mddev->queue; + blk_init_queue(q, DEVICE_REQUEST); + blk_queue_pluggable(q, md_plug_device); + blk_queue_make_request(q, md_make_request); + + q->plug_tq.sync = 0; + q->plug_tq.routine = &md_unplug_device; + q->plug_tq.data = mddev; /* - * Read the superblock, it's at the end of the disk + * The 'base' mddev is the one with data NULL. + * personalities can create additional mddevs + * if necessary. */ - rdev->sb_offset = MD_NEW_SIZE_BLOCKS (blk_size[MAJOR(dev)][MINOR(dev)]); - set_blocksize (dev, MD_SB_BYTES); - bh = bread (dev, rdev->sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); + add_mddev_mapping(mddev, dev, 0); + md_list_add(&mddev->all_mddevs, &all_mddevs); - if (bh) { - sb = (md_superblock_t *) bh->b_data; - if (sb->md_magic != MD_SB_MAGIC) { - printk (BAD_MAGIC, kdevname(dev), - sb->md_magic, rdev->sb_offset); - goto abort; - } - rdev->sb = (md_superblock_t *) __get_free_page(GFP_KERNEL); - if (!rdev->sb) { - printk (OUT_OF_MEM); - goto abort; - } - memcpy (rdev->sb, bh->b_data, MD_SB_BYTES); - - rdev->size = sb->size; - } else - printk (NO_DEVICE,kdevname(rdev->dev)); - ret = SUCCESS; -abort: - if (bh) - brelse (bh); - return ret; + return mddev; } -#undef SUCCESS -#undef FAILURE +static void free_mddev (mddev_t *mddev) +{ + if (!mddev) { + MD_BUG(); + return; + } -#undef BAD_MAGIC -#undef OUT_OF_MEM -#undef NO_DEVICE + /* + * Make sure nobody else is using this mddev + * (careful, we rely on the global kernel lock here) + */ + while (md_atomic_read(&mddev->resync_sem.count) != 1) + schedule(); + while (md_atomic_read(&mddev->recovery_sem.count) != 1) + schedule(); -/* - * Check a full RAID array for plausibility - */ + del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); + md_list_del(&mddev->all_mddevs); + MD_INIT_LIST_HEAD(&mddev->all_mddevs); + kfree(mddev); +} -#define INCONSISTENT KERN_ERR \ -"md: superblock inconsistency -- run ckraid\n" +struct gendisk * find_gendisk (kdev_t dev) +{ + struct gendisk *tmp = gendisk_head; -#define OUT_OF_DATE KERN_ERR \ -"md: superblock update time inconsistenty -- using the most recent one\n" + while (tmp != NULL) { + if (tmp->major == MAJOR(dev)) + return (tmp); + tmp = tmp->next; + } + return (NULL); +} -#define OLD_VERSION KERN_ALERT \ -"md: %s: unsupported raid array version %d.%d.%d\n" +mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) +{ + mdk_rdev_t * rdev; + struct md_list_head *tmp; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == nr) + return rdev; + } + return NULL; +} -#define NOT_CLEAN KERN_ERR \ -"md: %s: raid array is not clean -- run ckraid\n" +mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; -#define NOT_CLEAN_IGNORE KERN_ERR \ -"md: %s: raid array is not clean -- reconstructing parity\n" + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->dev == dev) + return rdev; + } + return NULL; +} -#define UNKNOWN_LEVEL KERN_ERR \ -"md: %s: unsupported raid level %d\n" +static MD_LIST_HEAD(device_names); -static int analyze_sbs (int minor, int pnum) +char * partition_name (kdev_t dev) { - struct md_dev *mddev = md_dev + minor; - int i, N = mddev->nb_dev, out_of_date = 0; - struct real_dev * disks = mddev->devices; - md_superblock_t *sb, *freshest = NULL; + struct gendisk *hd; + static char nomem [] = ""; + dev_name_t *dname; + struct md_list_head *tmp = device_names.next; + while (tmp != &device_names) { + dname = md_list_entry(tmp, dev_name_t, list); + if (dname->dev == dev) + return dname->name; + tmp = tmp->next; + } + + dname = (dev_name_t *) kmalloc(sizeof(*dname), GFP_KERNEL); + + if (!dname) + return nomem; /* - * RAID-0 and linear don't use a RAID superblock + * ok, add this new device name to the list */ - if (pnum == RAID0 >> PERSONALITY_SHIFT || - pnum == LINEAR >> PERSONALITY_SHIFT) - return legacy_raid_sb (minor, pnum); + hd = find_gendisk (dev); + + if (!hd) + sprintf (dname->name, "[dev %s]", kdevname(dev)); + else + disk_name (hd, MINOR(dev), dname->name); + + dname->dev = dev; + MD_INIT_LIST_HEAD(&dname->list); + md_list_add(&dname->list, &device_names); + + return dname->name; +} +static unsigned int calc_dev_sboffset (kdev_t dev, mddev_t *mddev, + int persistent) +{ + unsigned int size = 0; + + if (blk_size[MAJOR(dev)]) + size = blk_size[MAJOR(dev)][MINOR(dev)]; + if (persistent) + size = MD_NEW_SIZE_BLOCKS(size); + return size; +} + +static unsigned int calc_dev_size (kdev_t dev, mddev_t *mddev, int persistent) +{ + unsigned int size; + + size = calc_dev_sboffset(dev, mddev, persistent); + if (!mddev->sb) { + MD_BUG(); + return size; + } + if (mddev->sb->chunk_size) + size &= ~(mddev->sb->chunk_size/1024 - 1); + return size; +} + +static unsigned int zoned_raid_size (mddev_t *mddev) +{ + unsigned int mask; + mdk_rdev_t * rdev; + struct md_list_head *tmp; + + if (!mddev->sb) { + MD_BUG(); + return -EINVAL; + } /* - * Verify the RAID superblock on each real device + * do size and offset calculations. */ - for (i = 0; i < N; i++) - if (analyze_one_sb(disks+i)) - goto abort; + mask = ~(mddev->sb->chunk_size/1024 - 1); + + ITERATE_RDEV(mddev,rdev,tmp) { + rdev->size &= mask; + md_size[mdidx(mddev)] += rdev->size; + } + return 0; +} + +/* + * We check wether all devices are numbered from 0 to nb_dev-1. The + * order is guaranteed even after device name changes. + * + * Some personalities (raid0, linear) use this. Personalities that + * provide data have to be able to deal with loss of individual + * disks, so they do their checking themselves. + */ +int md_check_ordering (mddev_t *mddev) +{ + int i, c; + mdk_rdev_t *rdev; + struct md_list_head *tmp; /* - * The superblock constant part has to be the same - * for all disks in the array. + * First, all devices must be fully functional */ - sb = NULL; - for (i = 0; i < N; i++) { - if (!disks[i].sb) - continue; - if (!sb) { - sb = disks[i].sb; - continue; - } - if (memcmp(sb, - disks[i].sb, MD_SB_GENERIC_CONSTANT_WORDS * 4)) { - printk (INCONSISTENT); + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) { + printk("md: md%d's device %s faulty, aborting.\n", + mdidx(mddev), partition_name(rdev->dev)); goto abort; } } - /* - * OK, we have all disks and the array is ready to run. Let's - * find the freshest superblock, that one will be the superblock - * that represents the whole array. - */ - if ((sb = mddev->sb = (md_superblock_t *) __get_free_page (GFP_KERNEL)) == NULL) + c = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + c++; + } + if (c != mddev->nb_dev) { + MD_BUG(); goto abort; - freshest = NULL; - for (i = 0; i < N; i++) { - if (!disks[i].sb) - continue; - if (!freshest) { - freshest = disks[i].sb; - continue; - } - /* - * Find the newest superblock version - */ - if (disks[i].sb->utime != freshest->utime) { - out_of_date = 1; - if (disks[i].sb->utime > freshest->utime) - freshest = disks[i].sb; - } } - if (out_of_date) - printk(OUT_OF_DATE); - memcpy (sb, freshest, sizeof(*freshest)); - - /* - * Check if we can support this RAID array - */ - if (sb->major_version != MD_MAJOR_VERSION || - sb->minor_version > MD_MINOR_VERSION) { - - printk (OLD_VERSION, kdevname(MKDEV(MD_MAJOR, minor)), - sb->major_version, sb->minor_version, - sb->patch_version); + if (mddev->nb_dev != mddev->sb->raid_disks) { + printk("md: md%d, array needs %d disks, has %d, aborting.\n", + mdidx(mddev), mddev->sb->raid_disks, mddev->nb_dev); goto abort; } - /* - * We need to add this as a superblock option. + * Now the numbering check */ -#if SUPPORT_RECONSTRUCTION - if (sb->state != (1 << MD_SB_CLEAN)) { - if (sb->level == 1) { - printk (NOT_CLEAN, kdevname(MKDEV(MD_MAJOR, minor))); + for (i = 0; i < mddev->nb_dev; i++) { + c = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == i) + c++; + } + if (c == 0) { + printk("md: md%d, missing disk #%d, aborting.\n", + mdidx(mddev), i); goto abort; - } else - printk (NOT_CLEAN_IGNORE, kdevname(MKDEV(MD_MAJOR, minor))); - } -#else - if (sb->state != (1 << MD_SB_CLEAN)) { - printk (NOT_CLEAN, kdevname(MKDEV(MD_MAJOR, minor))); - goto abort; - } -#endif /* SUPPORT_RECONSTRUCTION */ - - switch (sb->level) { - case 1: - md_size[minor] = sb->size; - md_maxreadahead[minor] = MD_DEFAULT_DISK_READAHEAD; - break; - case 4: - case 5: - md_size[minor] = sb->size * (sb->raid_disks - 1); - md_maxreadahead[minor] = MD_DEFAULT_DISK_READAHEAD * (sb->raid_disks - 1); - break; - default: - printk (UNKNOWN_LEVEL, kdevname(MKDEV(MD_MAJOR, minor)), - sb->level); + } + if (c > 1) { + printk("md: md%d, too many disks #%d, aborting.\n", + mdidx(mddev), i); goto abort; + } } return 0; abort: - free_sb(mddev); return 1; } -#undef INCONSISTENT -#undef OUT_OF_DATE -#undef OLD_VERSION -#undef NOT_CLEAN -#undef OLD_LEVEL - -int md_update_sb(int minor) +static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb) { - struct md_dev *mddev = md_dev + minor; - struct buffer_head *bh; - md_superblock_t *sb = mddev->sb; - struct real_dev *realdev; - kdev_t dev; - int i; - u32 sb_offset; + if (disk_active(disk)) { + sb->working_disks--; + } else { + if (disk_spare(disk)) { + sb->spare_disks--; + sb->working_disks--; + } else { + sb->failed_disks--; + } + } + sb->nr_disks--; + disk->major = 0; + disk->minor = 0; + mark_disk_removed(disk); +} - sb->utime = CURRENT_TIME; - for (i = 0; i < mddev->nb_dev; i++) { - realdev = mddev->devices + i; - if (!realdev->sb) - continue; - dev = realdev->dev; - sb_offset = realdev->sb_offset; - set_blocksize(dev, MD_SB_BYTES); - printk("md: updating raid superblock on device %s, sb_offset == %u\n", kdevname(dev), sb_offset); - bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - if (bh) { - sb = (md_superblock_t *) bh->b_data; - memcpy(sb, mddev->sb, MD_SB_BYTES); - memcpy(&sb->descriptor, sb->disks + realdev->sb->descriptor.number, MD_SB_DESCRIPTOR_WORDS * 4); - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 1); - ll_rw_block(WRITE, 1, &bh); - wait_on_buffer(bh); - bforget(bh); - fsync_dev(dev); - invalidate_buffers(dev); - } else - printk(KERN_ERR "md: getblk failed for device %s\n", kdevname(dev)); +#define BAD_MAGIC KERN_ERR \ +"md: invalid raid superblock magic on %s\n" + +#define BAD_MINOR KERN_ERR \ +"md: %s: invalid raid minor (%x)\n" + +#define OUT_OF_MEM KERN_ALERT \ +"md: out of memory.\n" + +#define NO_SB KERN_ERR \ +"md: disabled device %s, could not read superblock.\n" + +#define BAD_CSUM KERN_WARNING \ +"md: invalid superblock checksum on %s\n" + +static int alloc_array_sb (mddev_t * mddev) +{ + if (mddev->sb) { + MD_BUG(); + return 0; } + + mddev->sb = (mdp_super_t *) __get_free_page (GFP_KERNEL); + if (!mddev->sb) + return -ENOMEM; + md_clear_page((unsigned long)mddev->sb); return 0; } -static int do_md_run (int minor, int repart) +static int alloc_disk_sb (mdk_rdev_t * rdev) { - int pnum, i, min, factor, err; + if (rdev->sb) + MD_BUG(); - if (!md_dev[minor].nb_dev) - return -EINVAL; - - if (md_dev[minor].pers) - return -EBUSY; - - md_dev[minor].repartition=repart; - - if ((pnum=PERSONALITY(&md_dev[minor]) >> (PERSONALITY_SHIFT)) - >= MAX_PERSONALITY) - return -EINVAL; - - /* Only RAID-1 and RAID-5 can have MD devices as underlying devices */ - if (pnum != (RAID1 >> PERSONALITY_SHIFT) && pnum != (RAID5 >> PERSONALITY_SHIFT)){ - for (i = 0; i < md_dev [minor].nb_dev; i++) - if (MAJOR (md_dev [minor].devices [i].dev) == MD_MAJOR) - return -EINVAL; - } - if (!pers[pnum]) - { -#ifdef CONFIG_KMOD - char module_name[80]; - sprintf (module_name, "md-personality-%d", pnum); - request_module (module_name); - if (!pers[pnum]) -#endif - return -EINVAL; - } - - factor = min = 1 << FACTOR_SHIFT(FACTOR((md_dev+minor))); - - for (i=0; isb = (mdp_super_t *) __get_free_page(GFP_KERNEL); + if (!rdev->sb) { + printk (OUT_OF_MEM); + return -EINVAL; + } + md_clear_page((unsigned long)rdev->sb); - md_dev[minor].pers=pers[pnum]; - - if ((err=md_dev[minor].pers->run (minor, md_dev+minor))) - { - md_dev[minor].pers=NULL; - free_sb(md_dev + minor); - return (err); - } - - if (pnum != RAID0 >> PERSONALITY_SHIFT && pnum != LINEAR >> PERSONALITY_SHIFT) - { - md_dev[minor].sb->state &= ~(1 << MD_SB_CLEAN); - md_update_sb(minor); - } - - /* FIXME : We assume here we have blocks - that are twice as large as sectors. - THIS MAY NOT BE TRUE !!! */ - md_hd_struct[minor].start_sect=0; - md_hd_struct[minor].nr_sects=md_size[minor]<<1; - - read_ahead[MD_MAJOR] = 128; - return (0); + return 0; } -static int do_md_stop (int minor, struct inode *inode) +static void free_disk_sb (mdk_rdev_t * rdev) { - int i; - - if (inode->i_count>1 || md_dev[minor].busy>1) { - /* - * ioctl : one open channel - */ - printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", - minor, inode->i_count, md_dev[minor].busy); - return -EBUSY; - } - - if (md_dev[minor].pers) { - /* - * It is safe to call stop here, it only frees private - * data. Also, it tells us if a device is unstoppable - * (eg. resyncing is in progress) - */ - if (md_dev[minor].pers->stop (minor, md_dev+minor)) - return -EBUSY; - /* - * The device won't exist anymore -> flush it now - */ - fsync_dev (inode->i_rdev); - invalidate_buffers (inode->i_rdev); - if (md_dev[minor].sb) { - md_dev[minor].sb->state |= 1 << MD_SB_CLEAN; - md_update_sb(minor); - } + if (rdev->sb) { + free_page((unsigned long) rdev->sb); + rdev->sb = NULL; + rdev->sb_offset = 0; + rdev->size = 0; + } else { + if (!rdev->faulty) + MD_BUG(); } - - /* Remove locks. */ - if (md_dev[minor].sb) - free_sb(md_dev + minor); - for (i=0; ifaulty = 1; +} - if (md_dev[minor].nb_dev==MAX_REAL) - return -EINVAL; +static int read_disk_sb (mdk_rdev_t * rdev) +{ + int ret = -EINVAL; + struct buffer_head *bh = NULL; + kdev_t dev = rdev->dev; + mdp_super_t *sb; + u32 sb_offset; - if (!fs_may_mount (dev)) + if (!rdev->sb) { + MD_BUG(); + goto abort; + } + + /* + * Calculate the position of the superblock, + * it's at the end of the disk + */ + sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1); + rdev->sb_offset = sb_offset; + printk("(read) %s's sb offset: %d", partition_name(dev), + sb_offset); + fsync_dev(dev); + set_blocksize (dev, MD_SB_BYTES); + bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); + + if (bh) { + sb = (mdp_super_t *) bh->b_data; + memcpy (rdev->sb, sb, MD_SB_BYTES); + } else { + printk (NO_SB,partition_name(rdev->dev)); + goto abort; + } + printk(" [events: %08lx]\n", (unsigned long)get_unaligned(&rdev->sb->events)); + ret = 0; +abort: + if (bh) + brelse (bh); + return ret; +} + +static unsigned int calc_sb_csum (mdp_super_t * sb) +{ + unsigned int disk_csum, csum; + + disk_csum = sb->sb_csum; + sb->sb_csum = 0; + csum = csum_partial((void *)sb, MD_SB_BYTES, 0); + sb->sb_csum = disk_csum; + return csum; +} + +/* + * Check one RAID superblock for generic plausibility + */ + +static int check_disk_sb (mdk_rdev_t * rdev) +{ + mdp_super_t *sb; + int ret = -EINVAL; + + sb = rdev->sb; + if (!sb) { + MD_BUG(); + goto abort; + } + + if (sb->md_magic != MD_SB_MAGIC) { + printk (BAD_MAGIC, partition_name(rdev->dev)); + goto abort; + } + + if (sb->md_minor >= MAX_MD_DEVS) { + printk (BAD_MINOR, partition_name(rdev->dev), + sb->md_minor); + goto abort; + } + + if (calc_sb_csum(sb) != sb->sb_csum) + printk(BAD_CSUM, partition_name(rdev->dev)); + ret = 0; +abort: + return ret; +} + +static kdev_t dev_unit(kdev_t dev) +{ + unsigned int mask; + struct gendisk *hd = find_gendisk(dev); + + if (!hd) + return 0; + mask = ~((1 << hd->minor_shift) - 1); + + return MKDEV(MAJOR(dev), MINOR(dev) & mask); +} + +static mdk_rdev_t * match_dev_unit(mddev_t *mddev, kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + ITERATE_RDEV(mddev,rdev,tmp) + if (dev_unit(rdev->dev) == dev_unit(dev)) + return rdev; + + return NULL; +} + +static MD_LIST_HEAD(all_raid_disks); +static MD_LIST_HEAD(pending_raid_disks); + +static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) +{ + mdk_rdev_t *same_pdev; + + if (rdev->mddev) { + MD_BUG(); + return; + } + same_pdev = match_dev_unit(mddev, rdev->dev); + if (same_pdev) + printk( KERN_WARNING +"md%d: WARNING: %s appears to be on the same physical disk as %s. True\n" +" protection against single-disk failure might be compromised.\n", + mdidx(mddev), partition_name(rdev->dev), + partition_name(same_pdev->dev)); + + md_list_add(&rdev->same_set, &mddev->disks); + rdev->mddev = mddev; + mddev->nb_dev++; + printk("bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev); +} + +static void unbind_rdev_from_array (mdk_rdev_t * rdev) +{ + if (!rdev->mddev) { + MD_BUG(); + return; + } + md_list_del(&rdev->same_set); + MD_INIT_LIST_HEAD(&rdev->same_set); + rdev->mddev->nb_dev--; + printk("unbind<%s,%d>\n", partition_name(rdev->dev), + rdev->mddev->nb_dev); + rdev->mddev = NULL; +} + +/* + * prevent the device from being mounted, repartitioned or + * otherwise reused by a RAID array (or any other kernel + * subsystem), by opening the device. [simply getting an + * inode is not enough, the SCSI module usage code needs + * an explicit open() on the device] + */ +static int lock_rdev (mdk_rdev_t *rdev) +{ + int err = 0; + + /* + * First insert a dummy inode. + */ + if (rdev->inode) + MD_BUG(); + rdev->inode = get_empty_inode(); + if (!rdev->inode) + return -ENOMEM; + /* + * we dont care about any other fields + */ + rdev->inode->i_dev = rdev->inode->i_rdev = rdev->dev; + insert_inode_hash(rdev->inode); + + memset(&rdev->filp, 0, sizeof(rdev->filp)); + rdev->filp.f_mode = 3; /* read write */ + return err; +} + +static void unlock_rdev (mdk_rdev_t *rdev) +{ + if (!rdev->inode) + MD_BUG(); + iput(rdev->inode); + rdev->inode = NULL; +} + +static void export_rdev (mdk_rdev_t * rdev) +{ + printk("export_rdev(%s)\n",partition_name(rdev->dev)); + if (rdev->mddev) + MD_BUG(); + unlock_rdev(rdev); + free_disk_sb(rdev); + md_list_del(&rdev->all); + MD_INIT_LIST_HEAD(&rdev->all); + if (rdev->pending.next != &rdev->pending) { + printk("(%s was pending)\n",partition_name(rdev->dev)); + md_list_del(&rdev->pending); + MD_INIT_LIST_HEAD(&rdev->pending); + } + rdev->dev = 0; + rdev->faulty = 0; + kfree(rdev); +} + +static void kick_rdev_from_array (mdk_rdev_t * rdev) +{ + unbind_rdev_from_array(rdev); + export_rdev(rdev); +} + +static void export_array (mddev_t *mddev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + mdp_super_t *sb = mddev->sb; + + if (mddev->sb) { + mddev->sb = NULL; + free_page((unsigned long) sb); + } + + ITERATE_RDEV(mddev,rdev,tmp) { + if (!rdev->mddev) { + MD_BUG(); + continue; + } + kick_rdev_from_array(rdev); + } + if (mddev->nb_dev) + MD_BUG(); +} + +#undef BAD_CSUM +#undef BAD_MAGIC +#undef OUT_OF_MEM +#undef NO_SB + +static void print_desc(mdp_disk_t *desc) +{ + printk(" DISK\n", desc->number, + partition_name(MKDEV(desc->major,desc->minor)), + desc->major,desc->minor,desc->raid_disk,desc->state); +} + +static void print_sb(mdp_super_t *sb) +{ + int i; + + printk(" SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", + sb->major_version, sb->minor_version, sb->patch_version, + sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3, + sb->ctime); + printk(" L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, + sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor, + sb->layout, sb->chunk_size); + printk(" UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n", + sb->utime, sb->state, sb->active_disks, sb->working_disks, + sb->failed_disks, sb->spare_disks, + sb->sb_csum, (unsigned long)get_unaligned(&sb->events)); + + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + + desc = sb->disks + i; + printk(" D %2d: ", i); + print_desc(desc); + } + printk(" THIS: "); + print_desc(&sb->this_disk); + +} + +static void print_rdev(mdk_rdev_t *rdev) +{ + printk(" rdev %s: O:%s, SZ:%08d F:%d DN:%d ", + partition_name(rdev->dev), partition_name(rdev->old_dev), + rdev->size, rdev->faulty, rdev->desc_nr); + if (rdev->sb) { + printk("rdev superblock:\n"); + print_sb(rdev->sb); + } else + printk("no rdev superblock!\n"); +} + +void md_print_devices (void) +{ + struct md_list_head *tmp, *tmp2; + mdk_rdev_t *rdev; + mddev_t *mddev; + + printk("\n"); + printk(" **********************************\n"); + printk(" * *\n"); + printk(" **********************************\n"); + ITERATE_MDDEV(mddev,tmp) { + printk("md%d: ", mdidx(mddev)); + + ITERATE_RDEV(mddev,rdev,tmp2) + printk("<%s>", partition_name(rdev->dev)); + + if (mddev->sb) { + printk(" array superblock:\n"); + print_sb(mddev->sb); + } else + printk(" no array superblock.\n"); + + ITERATE_RDEV(mddev,rdev,tmp2) + print_rdev(rdev); + } + printk(" **********************************\n"); + printk("\n"); +} + +static int sb_equal ( mdp_super_t *sb1, mdp_super_t *sb2) +{ + int ret; + mdp_super_t *tmp1, *tmp2; + + tmp1 = kmalloc(sizeof(*tmp1),GFP_KERNEL); + tmp2 = kmalloc(sizeof(*tmp2),GFP_KERNEL); + + if (!tmp1 || !tmp2) { + ret = 0; + goto abort; + } + + *tmp1 = *sb1; + *tmp2 = *sb2; + + /* + * nr_disks is not constant + */ + tmp1->nr_disks = 0; + tmp2->nr_disks = 0; + + if (memcmp(tmp1, tmp2, MD_SB_GENERIC_CONSTANT_WORDS * 4)) + ret = 0; + else + ret = 1; + +abort: + if (tmp1) + kfree(tmp1); + if (tmp2) + kfree(tmp2); + + return ret; +} + +static int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2) +{ + if ( (rdev1->sb->set_uuid0 == rdev2->sb->set_uuid0) && + (rdev1->sb->set_uuid1 == rdev2->sb->set_uuid1) && + (rdev1->sb->set_uuid2 == rdev2->sb->set_uuid2) && + (rdev1->sb->set_uuid3 == rdev2->sb->set_uuid3)) + + return 1; + + return 0; +} + +static mdk_rdev_t * find_rdev_all (kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + tmp = all_raid_disks.next; + while (tmp != &all_raid_disks) { + rdev = md_list_entry(tmp, mdk_rdev_t, all); + if (rdev->dev == dev) + return rdev; + tmp = tmp->next; + } + return NULL; +} + +#define GETBLK_FAILED KERN_ERR \ +"md: getblk failed for device %s\n" + +static int write_disk_sb(mdk_rdev_t * rdev) +{ + struct buffer_head *bh; + kdev_t dev; + u32 sb_offset, size; + mdp_super_t *sb; + + if (!rdev->sb) { + MD_BUG(); + return -1; + } + if (rdev->faulty) { + MD_BUG(); + return -1; + } + if (rdev->sb->md_magic != MD_SB_MAGIC) { + MD_BUG(); + return -1; + } + + dev = rdev->dev; + sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1); + if (rdev->sb_offset != sb_offset) { + printk("%s's sb offset has changed from %d to %d, skipping\n", partition_name(dev), rdev->sb_offset, sb_offset); + goto skip; + } + /* + * If the disk went offline meanwhile and it's just a spare, then + * it's size has changed to zero silently, and the MD code does + * not yet know that it's faulty. + */ + size = calc_dev_size(dev, rdev->mddev, 1); + if (size != rdev->size) { + printk("%s's size has changed from %d to %d since import, skipping\n", partition_name(dev), rdev->size, size); + goto skip; + } + + printk("(write) %s's sb offset: %d\n", partition_name(dev), sb_offset); + fsync_dev(dev); + set_blocksize(dev, MD_SB_BYTES); + bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); + if (!bh) { + printk(GETBLK_FAILED, partition_name(dev)); + return 1; + } + memset(bh->b_data,0,bh->b_size); + sb = (mdp_super_t *) bh->b_data; + memcpy(sb, rdev->sb, MD_SB_BYTES); + + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh, 1); + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + brelse(bh); + fsync_dev(dev); +skip: + return 0; +} +#undef GETBLK_FAILED KERN_ERR + +static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) +{ + int i, ok = 0; + mdp_disk_t *desc; + + for (i = 0; i < MD_SB_DISKS; i++) { + desc = mddev->sb->disks + i; +#if 0 + if (disk_faulty(desc)) { + if (MKDEV(desc->major,desc->minor) == rdev->dev) + ok = 1; + continue; + } +#endif + if (MKDEV(desc->major,desc->minor) == rdev->dev) { + rdev->sb->this_disk = *desc; + rdev->desc_nr = desc->number; + ok = 1; + break; + } + } + + if (!ok) { + MD_BUG(); + } +} + +static int sync_sbs(mddev_t * mddev) +{ + mdk_rdev_t *rdev; + mdp_super_t *sb; + struct md_list_head *tmp; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + sb = rdev->sb; + *sb = *mddev->sb; + set_this_disk(mddev, rdev); + sb->sb_csum = calc_sb_csum(sb); + } + return 0; +} + +int md_update_sb(mddev_t * mddev) +{ + int first, err, count = 100; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + __u64 ev; + +repeat: + mddev->sb->utime = CURRENT_TIME; + ev = get_unaligned(&mddev->sb->events); + ++ev; + put_unaligned(ev,&mddev->sb->events); + if (ev == (__u64)0) { + /* + * oops, this 64-bit counter should never wrap. + * Either we are in around ~1 trillion A.C., assuming + * 1 reboot per second, or we have a bug: + */ + MD_BUG(); + --ev; + put_unaligned(ev,&mddev->sb->events); + } + sync_sbs(mddev); + + /* + * do not write anything to disk if using + * nonpersistent superblocks + */ + if (mddev->sb->not_persistent) + return 0; + + printk(KERN_INFO "md: updating md%d RAID superblock on device\n", + mdidx(mddev)); + + first = 1; + err = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (!first) { + first = 0; + printk(", "); + } + if (rdev->faulty) + printk("(skipping faulty "); + printk("%s ", partition_name(rdev->dev)); + if (!rdev->faulty) { + printk("[events: %08lx]", + (unsigned long)get_unaligned(&rdev->sb->events)); + err += write_disk_sb(rdev); + } else + printk(")\n"); + } + printk(".\n"); + if (err) { + printk("errors occured during superblock update, repeating\n"); + if (--count) + goto repeat; + printk("excessive errors occured during superblock update, exiting\n"); + } + return 0; +} + +/* + * Import a device. If 'on_disk', then sanity check the superblock + * + * mark the device faulty if: + * + * - the device is nonexistent (zero size) + * - the device has no valid superblock + * + * a faulty rdev _never_ has rdev->sb set. + */ +static int md_import_device (kdev_t newdev, int on_disk) +{ + int err; + mdk_rdev_t *rdev; + unsigned int size; + + if (find_rdev_all(newdev)) + return -EEXIST; + + rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); + if (!rdev) { + printk("could not alloc mem for %s!\n", partition_name(newdev)); + return -ENOMEM; + } + memset(rdev, 0, sizeof(*rdev)); + + if (!fs_may_mount(newdev)) { + printk("md: can not import %s, has active inodes!\n", + partition_name(newdev)); + err = -EBUSY; + goto abort_free; + } + + if ((err = alloc_disk_sb(rdev))) + goto abort_free; + + rdev->dev = newdev; + if (lock_rdev(rdev)) { + printk("md: could not lock %s, zero-size? Marking faulty.\n", + partition_name(newdev)); + err = -EINVAL; + goto abort_free; + } + rdev->desc_nr = -1; + rdev->faulty = 0; + + size = 0; + if (blk_size[MAJOR(newdev)]) + size = blk_size[MAJOR(newdev)][MINOR(newdev)]; + if (!size) { + printk("md: %s has zero size, marking faulty!\n", + partition_name(newdev)); + err = -EINVAL; + goto abort_free; + } + + if (on_disk) { + if ((err = read_disk_sb(rdev))) { + printk("md: could not read %s's sb, not importing!\n", + partition_name(newdev)); + goto abort_free; + } + if ((err = check_disk_sb(rdev))) { + printk("md: %s has invalid sb, not importing!\n", + partition_name(newdev)); + goto abort_free; + } + + rdev->old_dev = MKDEV(rdev->sb->this_disk.major, + rdev->sb->this_disk.minor); + rdev->desc_nr = rdev->sb->this_disk.number; + } + md_list_add(&rdev->all, &all_raid_disks); + MD_INIT_LIST_HEAD(&rdev->pending); + + if (rdev->faulty && rdev->sb) + free_disk_sb(rdev); + return 0; + +abort_free: + if (rdev->sb) { + if (rdev->inode) + unlock_rdev(rdev); + free_disk_sb(rdev); + } + kfree(rdev); + return err; +} + +/* + * Check a full RAID array for plausibility + */ + +#define INCONSISTENT KERN_ERR \ +"md: fatal superblock inconsistency in %s -- removing from array\n" + +#define OUT_OF_DATE KERN_ERR \ +"md: superblock update time inconsistency -- using the most recent one\n" + +#define OLD_VERSION KERN_ALERT \ +"md: md%d: unsupported raid array version %d.%d.%d\n" + +#define NOT_CLEAN_IGNORE KERN_ERR \ +"md: md%d: raid array is not clean -- starting background reconstruction\n" + +#define UNKNOWN_LEVEL KERN_ERR \ +"md: md%d: unsupported raid level %d\n" + +static int analyze_sbs (mddev_t * mddev) +{ + int out_of_date = 0, i; + struct md_list_head *tmp, *tmp2; + mdk_rdev_t *rdev, *rdev2, *freshest; + mdp_super_t *sb; + + /* + * Verify the RAID superblock on each real device + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) { + MD_BUG(); + goto abort; + } + if (!rdev->sb) { + MD_BUG(); + goto abort; + } + if (check_disk_sb(rdev)) + goto abort; + } + + /* + * The superblock constant part has to be the same + * for all disks in the array. + */ + sb = NULL; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (!sb) { + sb = rdev->sb; + continue; + } + if (!sb_equal(sb, rdev->sb)) { + printk (INCONSISTENT, partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + continue; + } + } + + /* + * OK, we have all disks and the array is ready to run. Let's + * find the freshest superblock, that one will be the superblock + * that represents the whole array. + */ + if (!mddev->sb) + if (alloc_array_sb(mddev)) + goto abort; + sb = mddev->sb; + freshest = NULL; + + ITERATE_RDEV(mddev,rdev,tmp) { + __u64 ev1, ev2; + /* + * if the checksum is invalid, use the superblock + * only as a last resort. (decrease it's age by + * one event) + */ + if (calc_sb_csum(rdev->sb) != rdev->sb->sb_csum) { + __u64 ev = get_unaligned(&rdev->sb->events); + if (ev != (__u64)0) { + --ev; + put_unaligned(ev,&rdev->sb->events); + } + } + + printk("%s's event counter: %08lx\n", partition_name(rdev->dev), + (unsigned long)get_unaligned(&rdev->sb->events)); + if (!freshest) { + freshest = rdev; + continue; + } + /* + * Find the newest superblock version + */ + ev1 = get_unaligned(&rdev->sb->events); + ev2 = get_unaligned(&freshest->sb->events); + if (ev1 != ev2) { + out_of_date = 1; + if (ev1 > ev2) + freshest = rdev; + } + } + if (out_of_date) { + printk(OUT_OF_DATE); + printk("freshest: %s\n", partition_name(freshest->dev)); + } + memcpy (sb, freshest->sb, sizeof(*sb)); + + /* + * at this point we have picked the 'best' superblock + * from all available superblocks. + * now we validate this superblock and kick out possibly + * failed disks. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + /* + * Kick all non-fresh devices faulty + */ + __u64 ev1, ev2; + ev1 = get_unaligned(&rdev->sb->events); + ev2 = get_unaligned(&sb->events); + ++ev1; + if (ev1 < ev2) { + printk("md: kicking non-fresh %s from array!\n", + partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + continue; + } + } + + /* + * Fix up changed device names ... but only if this disk has a + * recent update time. Use faulty checksum ones too. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + __u64 ev1, ev2, ev3; + if (rdev->faulty) { /* REMOVEME */ + MD_BUG(); + goto abort; + } + ev1 = get_unaligned(&rdev->sb->events); + ev2 = get_unaligned(&sb->events); + ev3 = ev2; + --ev3; + if ((rdev->dev != rdev->old_dev) && + ((ev1 == ev2) || (ev1 == ev3))) { + mdp_disk_t *desc; + + printk("md: device name has changed from %s to %s since last import!\n", partition_name(rdev->old_dev), partition_name(rdev->dev)); + if (rdev->desc_nr == -1) { + MD_BUG(); + goto abort; + } + desc = &sb->disks[rdev->desc_nr]; + if (rdev->old_dev != MKDEV(desc->major, desc->minor)) { + MD_BUG(); + goto abort; + } + desc->major = MAJOR(rdev->dev); + desc->minor = MINOR(rdev->dev); + desc = &rdev->sb->this_disk; + desc->major = MAJOR(rdev->dev); + desc->minor = MINOR(rdev->dev); + } + } + + /* + * Remove unavailable and faulty devices ... + * + * note that if an array becomes completely unrunnable due to + * missing devices, we do not write the superblock back, so the + * administrator has a chance to fix things up. The removal thus + * only happens if it's nonfatal to the contents of the array. + */ + for (i = 0; i < MD_SB_DISKS; i++) { + int found; + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + /* + * We kick faulty devices/descriptors immediately. + */ + if (disk_faulty(desc)) { + found = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr != desc->number) + continue; + printk("md%d: kicking faulty %s!\n", + mdidx(mddev),partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + found = 1; + break; + } + if (!found) { + if (dev == MKDEV(0,0)) + continue; + printk("md%d: removing former faulty %s!\n", + mdidx(mddev), partition_name(dev)); + } + remove_descriptor(desc, sb); + continue; + } + + if (dev == MKDEV(0,0)) + continue; + /* + * Is this device present in the rdev ring? + */ + found = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == desc->number) { + found = 1; + break; + } + } + if (found) + continue; + + printk("md%d: former device %s is unavailable, removing from array!\n", mdidx(mddev), partition_name(dev)); + remove_descriptor(desc, sb); + } + + /* + * Double check wether all devices mentioned in the + * superblock are in the rdev ring. + */ + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + if (dev == MKDEV(0,0)) + continue; + + if (disk_faulty(desc)) { + MD_BUG(); + goto abort; + } + + rdev = find_rdev(mddev, dev); + if (!rdev) { + MD_BUG(); + goto abort; + } + } + + /* + * Do a final reality check. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == -1) { + MD_BUG(); + goto abort; + } + /* + * is the desc_nr unique? + */ + ITERATE_RDEV(mddev,rdev2,tmp2) { + if ((rdev2 != rdev) && + (rdev2->desc_nr == rdev->desc_nr)) { + MD_BUG(); + goto abort; + } + } + /* + * is the device unique? + */ + ITERATE_RDEV(mddev,rdev2,tmp2) { + if ((rdev2 != rdev) && + (rdev2->dev == rdev->dev)) { + MD_BUG(); + goto abort; + } + } + } + + /* + * Check if we can support this RAID array + */ + if (sb->major_version != MD_MAJOR_VERSION || + sb->minor_version > MD_MINOR_VERSION) { + + printk (OLD_VERSION, mdidx(mddev), sb->major_version, + sb->minor_version, sb->patch_version); + goto abort; + } + + if ((sb->state != (1 << MD_SB_CLEAN)) && ((sb->level == 1) || + (sb->level == 4) || (sb->level == 5))) + printk (NOT_CLEAN_IGNORE, mdidx(mddev)); + + return 0; +abort: + return 1; +} + +#undef INCONSISTENT +#undef OUT_OF_DATE +#undef OLD_VERSION +#undef OLD_LEVEL + +static int device_size_calculation (mddev_t * mddev) +{ + int data_disks = 0, persistent; + unsigned int readahead; + mdp_super_t *sb = mddev->sb; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + /* + * Do device size calculation. Bail out if too small. + * (we have to do this after having validated chunk_size, + * because device size has to be modulo chunk_size) + */ + persistent = !mddev->sb->not_persistent; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + if (rdev->size) { + MD_BUG(); + continue; + } + rdev->size = calc_dev_size(rdev->dev, mddev, persistent); + if (rdev->size < sb->chunk_size / 1024) { + printk (KERN_WARNING + "Dev %s smaller than chunk_size: %dk < %dk\n", + partition_name(rdev->dev), + rdev->size, sb->chunk_size / 1024); + return -EINVAL; + } + } + + switch (sb->level) { + case -3: + data_disks = 1; + break; + case -2: + data_disks = 1; + break; + case -1: + zoned_raid_size(mddev); + data_disks = 1; + break; + case 0: + zoned_raid_size(mddev); + data_disks = sb->raid_disks; + break; + case 1: + data_disks = 1; + break; + case 4: + case 5: + data_disks = sb->raid_disks-1; + break; + default: + printk (UNKNOWN_LEVEL, mdidx(mddev), sb->level); + goto abort; + } + if (!md_size[mdidx(mddev)]) + md_size[mdidx(mddev)] = sb->size * data_disks; + + readahead = MD_READAHEAD; + if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) + readahead = mddev->sb->chunk_size * 4 * data_disks; + if (readahead < data_disks * MAX_SECTORS*512*2) + readahead = data_disks * MAX_SECTORS*512*2; + else { + if (sb->level == -3) + readahead = 0; + } + md_maxreadahead[mdidx(mddev)] = readahead; + + printk(KERN_INFO "md%d: max total readahead window set to %dk\n", + mdidx(mddev), readahead/1024); + + printk(KERN_INFO + "md%d: %d data-disks, max readahead per data-disk: %dk\n", + mdidx(mddev), data_disks, readahead/data_disks/1024); + return 0; +abort: + return 1; +} + + +#define TOO_BIG_CHUNKSIZE KERN_ERR \ +"too big chunk_size: %d > %d\n" + +#define TOO_SMALL_CHUNKSIZE KERN_ERR \ +"too small chunk_size: %d < %ld\n" + +#define BAD_CHUNKSIZE KERN_ERR \ +"no chunksize specified, see 'man raidtab'\n" + +static int do_md_run (mddev_t * mddev) +{ + int pnum, err; + int chunk_size; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + + if (!mddev->nb_dev) { + MD_BUG(); + return -EINVAL; + } + + if (mddev->pers) + return -EBUSY; + + /* + * Resize disks to align partitions size on a given + * chunk size. + */ + md_size[mdidx(mddev)] = 0; + + /* + * Analyze all RAID superblock(s) + */ + if (analyze_sbs(mddev)) { + MD_BUG(); + return -EINVAL; + } + + chunk_size = mddev->sb->chunk_size; + pnum = level_to_pers(mddev->sb->level); + + mddev->param.chunk_size = chunk_size; + mddev->param.personality = pnum; + + if (chunk_size > MAX_CHUNK_SIZE) { + printk(TOO_BIG_CHUNKSIZE, chunk_size, MAX_CHUNK_SIZE); + return -EINVAL; + } + /* + * chunk-size has to be a power of 2 and multiples of PAGE_SIZE + */ + if ( (1 << ffz(~chunk_size)) != chunk_size) { + MD_BUG(); + return -EINVAL; + } + if (chunk_size < PAGE_SIZE) { + printk(TOO_SMALL_CHUNKSIZE, chunk_size, PAGE_SIZE); + return -EINVAL; + } + + if (pnum >= MAX_PERSONALITY) { + MD_BUG(); + return -EINVAL; + } + + if ((pnum != RAID1) && (pnum != LINEAR) && !chunk_size) { + /* + * 'default chunksize' in the old md code used to + * be PAGE_SIZE, baaad. + * we abort here to be on the safe side. We dont + * want to continue the bad practice. + */ + printk(BAD_CHUNKSIZE); + return -EINVAL; + } + + if (!pers[pnum]) + { +#ifdef CONFIG_KMOD + char module_name[80]; + sprintf (module_name, "md-personality-%d", pnum); + request_module (module_name); + if (!pers[pnum]) +#endif + return -EINVAL; + } + + if (device_size_calculation(mddev)) + return -EINVAL; + + /* + * Drop all container device buffers, from now on + * the only valid external interface is through the md + * device. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + fsync_dev(rdev->dev); + invalidate_buffers(rdev->dev); + } + + mddev->pers = pers[pnum]; + + err = mddev->pers->run(mddev); + if (err) { + printk("pers->run() failed ...\n"); + mddev->pers = NULL; + return -EINVAL; + } + + mddev->sb->state &= ~(1 << MD_SB_CLEAN); + md_update_sb(mddev); + + /* + * md_size has units of 1K blocks, which are + * twice as large as sectors. + */ + md_hd_struct[mdidx(mddev)].start_sect = 0; + md_hd_struct[mdidx(mddev)].nr_sects = md_size[mdidx(mddev)] << 1; + + read_ahead[MD_MAJOR] = 1024; + return (0); +} + +#undef TOO_BIG_CHUNKSIZE +#undef BAD_CHUNKSIZE + +#define OUT(x) do { err = (x); goto out; } while (0) + +static int restart_array (mddev_t *mddev) +{ + int err = 0; + + /* + * Complain if it has no devices + */ + if (!mddev->nb_dev) + OUT(-ENXIO); + + if (mddev->pers) { + if (!mddev->ro) + OUT(-EBUSY); + + mddev->ro = 0; + set_device_ro(mddev_to_kdev(mddev), 0); + + printk (KERN_INFO + "md%d switched to read-write mode.\n", mdidx(mddev)); + /* + * Kick recovery or resync if necessary + */ + md_recover_arrays(); + if (mddev->pers->restart_resync) + mddev->pers->restart_resync(mddev); + } else + err = -EINVAL; + +out: + return err; +} + +#define STILL_MOUNTED KERN_WARNING \ +"md: md%d still mounted.\n" + +static int do_md_stop (mddev_t * mddev, int ro) +{ + int err = 0, resync_interrupted = 0; + kdev_t dev = mddev_to_kdev(mddev); + + if (!ro && !fs_may_mount (dev)) { + printk (STILL_MOUNTED, mdidx(mddev)); + OUT(-EBUSY); + } + + /* + * complain if it's already stopped + */ + if (!mddev->nb_dev) + OUT(-ENXIO); + + if (mddev->pers) { + /* + * It is safe to call stop here, it only frees private + * data. Also, it tells us if a device is unstoppable + * (eg. resyncing is in progress) + */ + if (mddev->pers->stop_resync) + if (mddev->pers->stop_resync(mddev)) + resync_interrupted = 1; + + if (mddev->recovery_running) + md_interrupt_thread(md_recovery_thread); + + /* + * This synchronizes with signal delivery to the + * resync or reconstruction thread. It also nicely + * hangs the process if some reconstruction has not + * finished. + */ + down(&mddev->recovery_sem); + up(&mddev->recovery_sem); + + /* + * sync and invalidate buffers because we cannot kill the + * main thread with valid IO transfers still around. + * the kernel lock protects us from new requests being + * added after invalidate_buffers(). + */ + fsync_dev (mddev_to_kdev(mddev)); + fsync_dev (dev); + invalidate_buffers (dev); + + if (ro) { + if (mddev->ro) + OUT(-ENXIO); + mddev->ro = 1; + } else { + if (mddev->ro) + set_device_ro(dev, 0); + if (mddev->pers->stop(mddev)) { + if (mddev->ro) + set_device_ro(dev, 1); + OUT(-EBUSY); + } + if (mddev->ro) + mddev->ro = 0; + } + if (mddev->sb) { + /* + * mark it clean only if there was no resync + * interrupted. + */ + if (!mddev->recovery_running && !resync_interrupted) { + printk("marking sb clean...\n"); + mddev->sb->state |= 1 << MD_SB_CLEAN; + } + md_update_sb(mddev); + } + if (ro) + set_device_ro(dev, 1); + } + + /* + * Free resources if final stop + */ + if (!ro) { + export_array(mddev); + md_size[mdidx(mddev)] = 0; + md_hd_struct[mdidx(mddev)].nr_sects = 0; + free_mddev(mddev); + + printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); + } else + printk (KERN_INFO + "md%d switched to read-only mode.\n", mdidx(mddev)); +out: + return err; +} + +#undef OUT + +/* + * We have to safely support old arrays too. + */ +int detect_old_array (mdp_super_t *sb) +{ + if (sb->major_version > 0) + return 0; + if (sb->minor_version >= 90) + return 0; + + return -EINVAL; +} + + +static void autorun_array (mddev_t *mddev) +{ + mdk_rdev_t *rdev; + struct md_list_head *tmp; + int err; + + if (mddev->disks.prev == &mddev->disks) { + MD_BUG(); + return; + } + + printk("running: "); + + ITERATE_RDEV(mddev,rdev,tmp) { + printk("<%s>", partition_name(rdev->dev)); + } + printk("\nnow!\n"); + + err = do_md_run (mddev); + if (err) { + printk("do_md_run() returned %d\n", err); + /* + * prevent the writeback of an unrunnable array + */ + mddev->sb_dirty = 0; + do_md_stop (mddev, 0); + } +} + +/* + * lets try to run arrays based on all disks that have arrived + * until now. (those are in the ->pending list) + * + * the method: pick the first pending disk, collect all disks with + * the same UUID, remove all from the pending list and put them into + * the 'same_array' list. Then order this list based on superblock + * update time (freshest comes first), kick out 'old' disks and + * compare superblocks. If everything's fine then run it. + */ +static void autorun_devices (void) +{ + struct md_list_head candidates; + struct md_list_head *tmp; + mdk_rdev_t *rdev0, *rdev; + mddev_t *mddev; + kdev_t md_kdev; + + + printk("autorun ...\n"); + while (pending_raid_disks.next != &pending_raid_disks) { + rdev0 = md_list_entry(pending_raid_disks.next, + mdk_rdev_t, pending); + + printk("considering %s ...\n", partition_name(rdev0->dev)); + MD_INIT_LIST_HEAD(&candidates); + ITERATE_RDEV_PENDING(rdev,tmp) { + if (uuid_equal(rdev0, rdev)) { + if (!sb_equal(rdev0->sb, rdev->sb)) { + printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + continue; + } + printk(" adding %s ...\n", partition_name(rdev->dev)); + md_list_del(&rdev->pending); + md_list_add(&rdev->pending, &candidates); + } + } + /* + * now we have a set of devices, with all of them having + * mostly sane superblocks. It's time to allocate the + * mddev. + */ + md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); + mddev = kdev_to_mddev(md_kdev); + if (mddev) { + printk("md%d already running, cannot run %s\n", + mdidx(mddev), partition_name(rdev0->dev)); + ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) + export_rdev(rdev); + continue; + } + mddev = alloc_mddev(md_kdev); + printk("created md%d\n", mdidx(mddev)); + ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { + bind_rdev_to_array(rdev, mddev); + md_list_del(&rdev->pending); + MD_INIT_LIST_HEAD(&rdev->pending); + } + autorun_array(mddev); + } + printk("... autorun DONE.\n"); +} + +/* + * import RAID devices based on one partition + * if possible, the array gets run as well. + */ + +#define BAD_VERSION KERN_ERR \ +"md: %s has RAID superblock version 0.%d, autodetect needs v0.90 or higher\n" + +#define OUT_OF_MEM KERN_ALERT \ +"md: out of memory.\n" + +#define NO_DEVICE KERN_ERR \ +"md: disabled device %s\n" + +#define AUTOADD_FAILED KERN_ERR \ +"md: auto-adding devices to md%d FAILED (error %d).\n" + +#define AUTOADD_FAILED_USED KERN_ERR \ +"md: cannot auto-add device %s to md%d, already used.\n" + +#define AUTORUN_FAILED KERN_ERR \ +"md: auto-running md%d FAILED (error %d).\n" + +#define MDDEV_BUSY KERN_ERR \ +"md: cannot auto-add to md%d, already running.\n" + +#define AUTOADDING KERN_INFO \ +"md: auto-adding devices to md%d, based on %s's superblock.\n" + +#define AUTORUNNING KERN_INFO \ +"md: auto-running md%d.\n" + +static int autostart_array (kdev_t startdev) +{ + int err = -EINVAL, i; + mdp_super_t *sb = NULL; + mdk_rdev_t *start_rdev = NULL, *rdev; + + if (md_import_device(startdev, 1)) { + printk("could not import %s!\n", partition_name(startdev)); + goto abort; + } + + start_rdev = find_rdev_all(startdev); + if (!start_rdev) { + MD_BUG(); + goto abort; + } + if (start_rdev->faulty) { + printk("can not autostart based on faulty %s!\n", + partition_name(startdev)); + goto abort; + } + md_list_add(&start_rdev->pending, &pending_raid_disks); + + sb = start_rdev->sb; + + err = detect_old_array(sb); + if (err) { + printk("array version is too old to be autostarted, use raidtools 0.90 mkraid --upgrade\nto upgrade the array without data loss!\n"); + goto abort; + } + + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + if (dev == MKDEV(0,0)) + continue; + if (dev == startdev) + continue; + if (md_import_device(dev, 1)) { + printk("could not import %s, trying to run array nevertheless.\n", partition_name(dev)); + continue; + } + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + goto abort; + } + md_list_add(&rdev->pending, &pending_raid_disks); + } + + /* + * possibly return codes + */ + autorun_devices(); + return 0; + +abort: + if (start_rdev) + export_rdev(start_rdev); + return err; +} + +#undef BAD_VERSION +#undef OUT_OF_MEM +#undef NO_DEVICE +#undef AUTOADD_FAILED_USED +#undef AUTOADD_FAILED +#undef AUTORUN_FAILED +#undef AUTOADDING +#undef AUTORUNNING + +struct { + int set; + int noautodetect; + +} raid_setup_args md__initdata = { 0, 0 }; + +/* + * Searches all registered partitions for autorun RAID arrays + * at boot time. + */ +void md__init autodetect_raid(void) +{ +#ifdef CONFIG_AUTODETECT_RAID + struct gendisk *disk; + mdk_rdev_t *rdev; + int i; + + if (raid_setup_args.noautodetect) { + printk(KERN_INFO "skipping autodetection of RAID arrays\n"); + return; + } + printk(KERN_INFO "autodetecting RAID arrays\n"); + + for (disk = gendisk_head ; disk ; disk = disk->next) { + for (i = 0; i < disk->max_p*disk->nr_real; i++) { + kdev_t dev = MKDEV(disk->major,i); + + if (disk->part[i].type != LINUX_RAID_PARTITION) + continue; + + if (md_import_device(dev,1)) { + printk(KERN_ALERT "could not import %s!\n", + partition_name(dev)); + continue; + } + /* + * Sanity checks: + */ + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + continue; + } + if (rdev->faulty) { + MD_BUG(); + continue; + } + md_list_add(&rdev->pending, &pending_raid_disks); + } + } + + autorun_devices(); +#endif +} + +static int get_version (void * arg) +{ + mdu_version_t ver; + + ver.major = MD_MAJOR_VERSION; + ver.minor = MD_MINOR_VERSION; + ver.patchlevel = MD_PATCHLEVEL_VERSION; + + if (md_copy_to_user(arg, &ver, sizeof(ver))) + return -EFAULT; + + return 0; +} + +#define SET_FROM_SB(x) info.x = mddev->sb->x +static int get_array_info (mddev_t * mddev, void * arg) +{ + mdu_array_info_t info; + + if (!mddev->sb) + return -EINVAL; + + SET_FROM_SB(major_version); + SET_FROM_SB(minor_version); + SET_FROM_SB(patch_version); + SET_FROM_SB(ctime); + SET_FROM_SB(level); + SET_FROM_SB(size); + SET_FROM_SB(nr_disks); + SET_FROM_SB(raid_disks); + SET_FROM_SB(md_minor); + SET_FROM_SB(not_persistent); + + SET_FROM_SB(utime); + SET_FROM_SB(state); + SET_FROM_SB(active_disks); + SET_FROM_SB(working_disks); + SET_FROM_SB(failed_disks); + SET_FROM_SB(spare_disks); + + SET_FROM_SB(layout); + SET_FROM_SB(chunk_size); + + if (md_copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} +#undef SET_FROM_SB + +#define SET_FROM_SB(x) info.x = mddev->sb->disks[nr].x +static int get_disk_info (mddev_t * mddev, void * arg) +{ + mdu_disk_info_t info; + unsigned int nr; + + if (!mddev->sb) + return -EINVAL; + + if (md_copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + nr = info.number; + if (nr >= mddev->sb->nr_disks) + return -EINVAL; + + SET_FROM_SB(major); + SET_FROM_SB(minor); + SET_FROM_SB(raid_disk); + SET_FROM_SB(state); + + if (md_copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} +#undef SET_FROM_SB + +#define SET_SB(x) mddev->sb->disks[nr].x = info.x + +static int add_new_disk (mddev_t * mddev, void * arg) +{ + int err, size, persistent; + mdu_disk_info_t info; + mdk_rdev_t *rdev; + unsigned int nr; + kdev_t dev; + + if (!mddev->sb) + return -EINVAL; + + if (md_copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + nr = info.number; + if (nr >= mddev->sb->nr_disks) + return -EINVAL; + + dev = MKDEV(info.major,info.minor); + + if (find_rdev_all(dev)) { + printk("device %s already used in a RAID array!\n", + partition_name(dev)); + return -EBUSY; + } + + SET_SB(number); + SET_SB(major); + SET_SB(minor); + SET_SB(raid_disk); + SET_SB(state); + + if ((info.state & (1<old_dev = dev; + rdev->desc_nr = info.number; + + bind_rdev_to_array(rdev, mddev); + + persistent = !mddev->sb->not_persistent; + if (!persistent) + printk("nonpersistent superblock ...\n"); + if (!mddev->sb->chunk_size) + printk("no chunksize?\n"); + + size = calc_dev_size(dev, mddev, persistent); + rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); + + if (!mddev->sb->size || (mddev->sb->size > size)) + mddev->sb->size = size; + } + + /* + * sync all other superblocks with the main superblock + */ + sync_sbs(mddev); + + return 0; +} +#undef SET_SB + +static int hot_remove_disk (mddev_t * mddev, kdev_t dev) +{ + int err; + mdk_rdev_t *rdev; + mdp_disk_t *disk; + + if (!mddev->pers) + return -ENODEV; + + printk("trying to remove %s from md%d ... \n", + partition_name(dev), mdidx(mddev)); + + if (!mddev->pers->diskop) { + printk("md%d: personality does not support diskops!\n", + mdidx(mddev)); + return -EINVAL; + } + + rdev = find_rdev(mddev, dev); + if (!rdev) + return -ENXIO; + + if (rdev->desc_nr == -1) { + MD_BUG(); + return -EINVAL; + } + disk = &mddev->sb->disks[rdev->desc_nr]; + if (disk_active(disk)) + goto busy; + if (disk_removed(disk)) { + MD_BUG(); + return -EINVAL; + } + + err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); + if (err == -EBUSY) + goto busy; + if (err) { + MD_BUG(); + return -EINVAL; + } + + remove_descriptor(disk, mddev->sb); + kick_rdev_from_array(rdev); + mddev->sb_dirty = 1; + md_update_sb(mddev); + + return 0; +busy: + printk("cannot remove active disk %s from md%d ... \n", + partition_name(dev), mdidx(mddev)); + return -EBUSY; +} + +static int hot_add_disk (mddev_t * mddev, kdev_t dev) +{ + int i, err, persistent; + unsigned int size; + mdk_rdev_t *rdev; + mdp_disk_t *disk; + + if (!mddev->pers) + return -ENODEV; + + printk("trying to hot-add %s to md%d ... \n", + partition_name(dev), mdidx(mddev)); + + if (!mddev->pers->diskop) { + printk("md%d: personality does not support diskops!\n", + mdidx(mddev)); + return -EINVAL; + } + + persistent = !mddev->sb->not_persistent; + size = calc_dev_size(dev, mddev, persistent); + + if (size < mddev->sb->size) { + printk("md%d: disk size %d blocks < array size %d\n", + mdidx(mddev), size, mddev->sb->size); + return -ENOSPC; + } + + rdev = find_rdev(mddev, dev); + if (rdev) + return -EBUSY; + + err = md_import_device (dev, 0); + if (err) { + printk("md: error, md_import_device() returned %d\n", err); + return -EINVAL; + } + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + return -EINVAL; + } + if (rdev->faulty) { + printk("md: can not hot-add faulty %s disk to md%d!\n", + partition_name(dev), mdidx(mddev)); + err = -EINVAL; + goto abort_export; + } + bind_rdev_to_array(rdev, mddev); + + /* + * The rest should better be atomic, we can have disk failures + * noticed in interrupt contexts ... + */ + rdev->old_dev = dev; + rdev->size = size; + rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); + + disk = mddev->sb->disks + mddev->sb->raid_disks; + for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) { + disk = mddev->sb->disks + i; + + if (!disk->major && !disk->minor) + break; + if (disk_removed(disk)) + break; + } + if (i == MD_SB_DISKS) { + printk("md%d: can not hot-add to full array!\n", mdidx(mddev)); + err = -EBUSY; + goto abort_unbind_export; + } + + if (disk_removed(disk)) { + /* + * reuse slot + */ + if (disk->number != i) { + MD_BUG(); + err = -EINVAL; + goto abort_unbind_export; + } + } else { + disk->number = i; + } + + disk->raid_disk = disk->number; + disk->major = MAJOR(dev); + disk->minor = MINOR(dev); + + if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) { + MD_BUG(); + err = -EINVAL; + goto abort_unbind_export; + } + + mark_disk_spare(disk); + mddev->sb->nr_disks++; + mddev->sb->spare_disks++; + mddev->sb->working_disks++; + + mddev->sb_dirty = 1; + + md_update_sb(mddev); + + /* + * Kick recovery, maybe this spare has to be added to the + * array immediately. + */ + md_recover_arrays(); + + return 0; + +abort_unbind_export: + unbind_rdev_from_array(rdev); + +abort_export: + export_rdev(rdev); + return err; +} + +#define SET_SB(x) mddev->sb->x = info.x +static int set_array_info (mddev_t * mddev, void * arg) +{ + mdu_array_info_t info; + + if (mddev->sb) { + printk("array md%d already has a superblock!\n", + mdidx(mddev)); return -EBUSY; + } + + if (md_copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + if (alloc_array_sb(mddev)) + return -ENOMEM; + + mddev->sb->major_version = MD_MAJOR_VERSION; + mddev->sb->minor_version = MD_MINOR_VERSION; + mddev->sb->patch_version = MD_PATCHLEVEL_VERSION; + mddev->sb->ctime = CURRENT_TIME; + + SET_SB(level); + SET_SB(size); + SET_SB(nr_disks); + SET_SB(raid_disks); + SET_SB(md_minor); + SET_SB(not_persistent); + + SET_SB(state); + SET_SB(active_disks); + SET_SB(working_disks); + SET_SB(failed_disks); + SET_SB(spare_disks); + + SET_SB(layout); + SET_SB(chunk_size); + + mddev->sb->md_magic = MD_SB_MAGIC; + + /* + * Generate a 128 bit UUID + */ + get_random_bytes(&mddev->sb->set_uuid0, 4); + get_random_bytes(&mddev->sb->set_uuid1, 4); + get_random_bytes(&mddev->sb->set_uuid2, 4); + get_random_bytes(&mddev->sb->set_uuid3, 4); + + return 0; +} +#undef SET_SB + +static int set_disk_info (mddev_t * mddev, void * arg) +{ + printk("not yet"); + return -EINVAL; +} + +static int clear_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int write_raid_info (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int protect_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int unprotect_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int set_disk_faulty (mddev_t *mddev, kdev_t dev) +{ + int ret; + + fsync_dev(mddev_to_kdev(mddev)); + ret = md_error(mddev_to_kdev(mddev), dev); + return ret; +} + +static int md_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor; + int err = 0; + struct hd_geometry *loc = (struct hd_geometry *) arg; + mddev_t *mddev = NULL; + kdev_t dev; + + if (!md_capable_admin()) + return -EACCES; + + dev = inode->i_rdev; + minor = MINOR(dev); + if (minor >= MAX_MD_DEVS) + return -EINVAL; + + /* + * Commands dealing with the RAID driver but not any + * particular array: + */ + switch (cmd) + { + case RAID_VERSION: + err = get_version((void *)arg); + goto done; + + case PRINT_RAID_DEBUG: + err = 0; + md_print_devices(); + goto done_unlock; + + case BLKGETSIZE: /* Return device size */ + if (!arg) { + err = -EINVAL; + goto abort; + } + err = md_put_user(md_hd_struct[minor].nr_sects, + (long *) arg); + goto done; + + case BLKFLSBUF: + fsync_dev(dev); + invalidate_buffers(dev); + goto done; + + case BLKRASET: + if (arg > 0xff) { + err = -EINVAL; + goto abort; + } + read_ahead[MAJOR(dev)] = arg; + goto done; + + case BLKRAGET: + if (!arg) { + err = -EINVAL; + goto abort; + } + err = md_put_user (read_ahead[ + MAJOR(dev)], (long *) arg); + goto done; + default: + } + + /* + * Commands creating/starting a new array: + */ + + mddev = kdev_to_mddev(dev); + + switch (cmd) + { + case SET_ARRAY_INFO: + case START_ARRAY: + if (mddev) { + printk("array md%d already exists!\n", + mdidx(mddev)); + err = -EEXIST; + goto abort; + } + default: + } + + switch (cmd) + { + case SET_ARRAY_INFO: + mddev = alloc_mddev(dev); + if (!mddev) { + err = -ENOMEM; + goto abort; + } + /* + * alloc_mddev() should possibly self-lock. + */ + err = lock_mddev(mddev); + if (err) { + printk("ioctl, reason %d, cmd %d\n", err, cmd); + goto abort; + } + err = set_array_info(mddev, (void *)arg); + if (err) { + printk("couldnt set array info. %d\n", err); + goto abort; + } + goto done_unlock; + + case START_ARRAY: + /* + * possibly make it lock the array ... + */ + err = autostart_array((kdev_t)arg); + if (err) { + printk("autostart %s failed!\n", + partition_name((kdev_t)arg)); + goto abort; + } + goto done; + + default: + } + + /* + * Commands querying/configuring an existing array: + */ - if (blk_size[MAJOR(dev)] == NULL || blk_size[MAJOR(dev)][MINOR(dev)] == 0) { - printk("md_add(): zero device size, huh, bailing out.\n"); - return -EINVAL; + if (!mddev) { + err = -ENODEV; + goto abort; + } + err = lock_mddev(mddev); + if (err) { + printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); + goto abort; } - if (md_dev[minor].pers) { - /* - * The array is already running, hot-add the drive, or - * bail out: - */ - if (!md_dev[minor].pers->hot_add_disk) - return -EBUSY; - else - hot_add=1; + /* + * Commands even a read-only array can execute: + */ + switch (cmd) + { + case GET_ARRAY_INFO: + err = get_array_info(mddev, (void *)arg); + goto done_unlock; + + case GET_DISK_INFO: + err = get_disk_info(mddev, (void *)arg); + goto done_unlock; + + case RESTART_ARRAY_RW: + err = restart_array(mddev); + goto done_unlock; + + case STOP_ARRAY: + err = do_md_stop (mddev, 0); + goto done_unlock; + + case STOP_ARRAY_RO: + err = do_md_stop (mddev, 1); + goto done_unlock; + + /* + * We have a problem here : there is no easy way to give a CHS + * virtual geometry. We currently pretend that we have a 2 heads + * 4 sectors (with a BIG number of cylinders...). This drives + * dosfs just mad... ;-) + */ + case HDIO_GETGEO: + if (!loc) { + err = -EINVAL; + goto abort_unlock; + } + err = md_put_user (2, (char *) &loc->heads); + if (err) + goto abort_unlock; + err = md_put_user (4, (char *) &loc->sectors); + if (err) + goto abort_unlock; + err = md_put_user (md_hd_struct[mdidx(mddev)].nr_sects/8, + (short *) &loc->cylinders); + if (err) + goto abort_unlock; + err = md_put_user (md_hd_struct[minor].start_sect, + (long *) &loc->start); + goto done_unlock; } /* - * Careful. We cannot increase nb_dev for a running array. + * The remaining ioctls are changing the state of the + * superblock, so we do not allow read-only arrays + * here: */ - i=md_dev[minor].nb_dev; - realdev = &md_dev[minor].devices[i]; - realdev->dev=dev; - - /* Lock the device by inserting a dummy inode. This doesn't - smell very good, but I need to be consistent with the - mount stuff, specially with fs_may_mount. If someone have - a better idea, please help ! */ - - realdev->inode=get_empty_inode (); - if (!realdev->inode) - return -ENOMEM; - realdev->inode->i_dev=dev; /* don't care about other fields */ - insert_inode_hash (realdev->inode); - - /* Sizes are now rounded at run time */ - -/* md_dev[minor].devices[i].size=gen_real->sizes[MINOR(dev)]; HACKHACK*/ + if (mddev->ro) { + err = -EROFS; + goto abort_unlock; + } + + switch (cmd) + { + case CLEAR_ARRAY: + err = clear_array(mddev); + goto done_unlock; + + case ADD_NEW_DISK: + err = add_new_disk(mddev, (void *)arg); + goto done_unlock; + + case HOT_REMOVE_DISK: + err = hot_remove_disk(mddev, (kdev_t)arg); + goto done_unlock; + + case HOT_ADD_DISK: + err = hot_add_disk(mddev, (kdev_t)arg); + goto done_unlock; + + case SET_DISK_INFO: + err = set_disk_info(mddev, (void *)arg); + goto done_unlock; + + case WRITE_RAID_INFO: + err = write_raid_info(mddev); + goto done_unlock; + + case UNPROTECT_ARRAY: + err = unprotect_array(mddev); + goto done_unlock; + + case PROTECT_ARRAY: + err = protect_array(mddev); + goto done_unlock; + + case SET_DISK_FAULTY: + err = set_disk_faulty(mddev, (kdev_t)arg); + goto done_unlock; - realdev->size=blk_size[MAJOR(dev)][MINOR(dev)]; + case RUN_ARRAY: + { + mdu_param_t param; - if (hot_add) { - /* - * Check the superblock for consistency. - * The personality itself has to check whether it's getting - * added with the proper flags. The personality has to be - * checked too. ;) - */ - if (analyze_one_sb (realdev)) - return -EINVAL; - /* - * hot_add has to bump up nb_dev itself - */ - if (md_dev[minor].pers->hot_add_disk (&md_dev[minor], dev)) { + err = md_copy_from_user(¶m, (mdu_param_t *)arg, + sizeof(param)); + if (err) + goto abort_unlock; + + err = do_md_run (mddev); /* - * FIXME: here we should free up the inode and stuff + * we have to clean up the mess if + * the array cannot be run for some + * reason ... */ - printk ("FIXME\n"); - return -EINVAL; + if (err) { + mddev->sb_dirty = 0; + do_md_stop (mddev, 0); + } + goto done_unlock; } - } else - md_dev[minor].nb_dev++; - - printk ("REGISTER_DEV %s to md%x done\n", partition_name(dev), minor); - return (0); -} - -static int md_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int minor, err; - struct hd_geometry *loc = (struct hd_geometry *) arg; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (((minor=MINOR(inode->i_rdev)) & 0x80) && - (minor & 0x7f) < MAX_PERSONALITY && - pers[minor & 0x7f] && - pers[minor & 0x7f]->ioctl) - return (pers[minor & 0x7f]->ioctl (inode, file, cmd, arg)); - - if (minor >= MAX_MD_DEV) - return -EINVAL; + default: + printk(KERN_WARNING "%s(pid %d) used obsolete MD ioctl, upgrade your software to use new ictls.\n", current->comm, current->pid); + err = -EINVAL; + goto abort_unlock; + } - switch (cmd) - { - case REGISTER_DEV: - return do_md_add (minor, to_kdev_t ((dev_t) arg)); - - case START_MD: - return do_md_run (minor, (int) arg); - - case STOP_MD: - return do_md_stop (minor, inode); - - case BLKGETSIZE: /* Return device size */ - if (!arg) return -EINVAL; - err = put_user (md_hd_struct[MINOR(inode->i_rdev)].nr_sects, (long *) arg); - if (err) - return err; - break; - - - /* We have a problem here : there is no easy way to give a CHS - virtual geometry. We currently pretend that we have a 2 heads - 4 sectors (with a BIG number of cylinders...). This drives dosfs - just mad... ;-) */ - - case HDIO_GETGEO: - if (!loc) return -EINVAL; - err = put_user (2, (char *) &loc->heads); - if (err) - return err; - err = put_user (4, (char *) &loc->sectors); - if (err) - return err; - err = put_user (md_hd_struct[minor].nr_sects/8, (short *) &loc->cylinders); - if (err) - return err; - err = put_user (md_hd_struct[MINOR(inode->i_rdev)].start_sect, - (long *) &loc->start); - if (err) - return err; - break; - - case BLKROSET: - case BLKROGET: - case BLKRAGET: - case BLKRASET: - case BLKFLSBUF: - return blk_ioctl(inode->i_rdev, cmd, arg); - - default: - return -EINVAL; - } +done_unlock: +abort_unlock: + if (mddev) + unlock_mddev(mddev); + else + printk("huh11?\n"); - return (0); + return err; +done: + if (err) + printk("huh12?\n"); +abort: + return err; } static int md_open (struct inode *inode, struct file *file) { - int minor=MINOR(inode->i_rdev); - - md_dev[minor].busy++; - return (0); /* Always succeed */ -} - - -static int md_release (struct inode *inode, struct file *file) -{ - int minor=MINOR(inode->i_rdev); - md_dev[minor].busy--; - return 0; + /* + * Always succeed + */ + return (0); } static struct block_device_operations md_fops= { open: md_open, - release: md_release, ioctl: md_ioctl, }; + -int md_map (int minor, kdev_t *rdev, unsigned long *rsector, unsigned long size) +int md_thread(void * arg) { - if ((unsigned int) minor >= MAX_MD_DEV) - { - printk ("Bad md device %d\n", minor); - return (-1); - } - - if (!md_dev[minor].pers) - { - printk ("Oops ! md%d not running, giving up !\n", minor); - return (-1); - } + mdk_thread_t *thread = arg; - return (md_dev[minor].pers->map(md_dev+minor, rdev, rsector, size)); -} - -int md_make_request (int minor, int rw, struct buffer_head * bh) -{ - if (md_dev [minor].pers->make_request) { - if (buffer_locked(bh)) - return 0; - set_bit(BH_Lock, &bh->b_state); - if (rw == WRITE) { - if (!buffer_dirty(bh)) { - bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); - return 0; - } + md_lock_kernel(); + exit_mm(current); + exit_files(current); + exit_fs(current); + + /* + * Detach thread + */ + sys_setsid(); + sprintf(current->comm, thread->name); + md_init_signals(); + md_flush_signals(); + thread->tsk = current; + + /* + * md_thread is a 'system-thread', it's priority should be very + * high. We avoid resource deadlocks individually in each + * raid personality. (RAID5 does preallocation) We also use RR and + * the very same RT priority as kswapd, thus we will never get + * into a priority inversion deadlock. + * + * we definitely have to have equal or higher priority than + * bdflush, otherwise bdflush will deadlock if there are too + * many dirty RAID5 blocks. + */ + current->policy = SCHED_OTHER; + current->priority = 40; +// md_unlock_kernel(); + + up(thread->sem); + + for (;;) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&thread->wqueue, &wait); + if (!test_bit(THREAD_WAKEUP, &thread->flags)) { + set_task_state(current, TASK_INTERRUPTIBLE); + dprintk("thread %p went to sleep.\n", thread); + schedule(); + dprintk("thread %p woke up.\n", thread); + current->state = TASK_RUNNING; } - if (rw == READ || rw == READA) { - if (buffer_uptodate(bh)) { - bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); - return 0; - } + remove_wait_queue(&thread->wqueue, &wait); + clear_bit(THREAD_WAKEUP, &thread->flags); + + if (thread->run) { + thread->run(thread->data); + run_task_queue(&tq_disk); + } else + break; + if (md_signal_pending(current)) { + printk("%8s(%d) flushing signals.\n", current->comm, + current->pid); + md_flush_signals(); } - return (md_dev[minor].pers->make_request(md_dev+minor, rw, bh)); - } else { - make_request (MAJOR(bh->b_rdev), rw, bh); - return 0; } + up(thread->sem); + return 0; } -static void do_md_request (request_queue_t * q) -{ - printk ("Got md request, not good..."); - return; -} - -void md_wakeup_thread(struct md_thread *thread) +void md_wakeup_thread(mdk_thread_t *thread) { + dprintk("waking up MD thread %p.\n", thread); set_bit(THREAD_WAKEUP, &thread->flags); wake_up(&thread->wqueue); } -struct md_thread *md_register_thread (void (*run) (void *), void *data) +mdk_thread_t *md_register_thread (void (*run) (void *), + void *data, const char *name) { - struct md_thread *thread = (struct md_thread *) - kmalloc(sizeof(struct md_thread), GFP_KERNEL); + mdk_thread_t *thread; int ret; DECLARE_MUTEX_LOCKED(sem); - if (!thread) return NULL; + thread = (mdk_thread_t *) kmalloc + (sizeof(mdk_thread_t), GFP_KERNEL); + if (!thread) + return NULL; - memset(thread, 0, sizeof(struct md_thread)); - init_waitqueue_head(&thread->wqueue); + memset(thread, 0, sizeof(mdk_thread_t)); + md_init_waitqueue_head(&thread->wqueue); thread->sem = &sem; thread->run = run; thread->data = data; + thread->name = name; ret = kernel_thread(md_thread, thread, 0); if (ret < 0) { kfree(thread); @@ -760,387 +2882,317 @@ return thread; } -void md_unregister_thread (struct md_thread *thread) +void md_interrupt_thread (mdk_thread_t *thread) +{ + if (!thread->tsk) { + MD_BUG(); + return; + } + printk("interrupting MD-thread pid %d\n", thread->tsk->pid); + send_sig(SIGKILL, thread->tsk, 1); +} + +void md_unregister_thread (mdk_thread_t *thread) { DECLARE_MUTEX_LOCKED(sem); thread->sem = &sem; thread->run = NULL; - if (thread->tsk) - printk("Killing md_thread %d %p %s\n", - thread->tsk->pid, thread->tsk, thread->tsk->comm); - else - printk("Aiee. md_thread has 0 tsk\n"); - send_sig(SIGKILL, thread->tsk, 1); - printk("downing on %p\n", &sem); + thread->name = NULL; + if (!thread->tsk) { + MD_BUG(); + return; + } + md_interrupt_thread(thread); down(&sem); } -#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) +void md_recover_arrays (void) +{ + if (!md_recovery_thread) { + MD_BUG(); + return; + } + md_wakeup_thread(md_recovery_thread); +} + -int md_thread(void * arg) +int md_error (kdev_t dev, kdev_t rdev) { - struct md_thread *thread = arg; + mddev_t *mddev = kdev_to_mddev(dev); + mdk_rdev_t * rrdev; + int rc; - lock_kernel(); - exit_mm(current); - exit_files(current); - exit_fs(current); - - current->session = 1; - current->pgrp = 1; - sprintf(current->comm, "md_thread"); - siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); - thread->tsk = current; - up(thread->sem); + printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3)); - for (;;) { - cli(); - if (!test_bit(THREAD_WAKEUP, &thread->flags)) { - do { - spin_lock(¤t->sigmask_lock); - flush_signals(current); - spin_unlock(¤t->sigmask_lock); - interruptible_sleep_on(&thread->wqueue); - cli(); - if (test_bit(THREAD_WAKEUP, &thread->flags)) - break; - if (!thread->run) { - sti(); - up(thread->sem); - return 0; - } - } while (signal_pending(current)); - } - sti(); - clear_bit(THREAD_WAKEUP, &thread->flags); - if (thread->run) { - thread->run(thread->data); - run_task_queue(&tq_disk); + if (!mddev) { + MD_BUG(); + return 0; + } + rrdev = find_rdev(mddev, rdev); + mark_rdev_faulty(rrdev); + /* + * if recovery was running, stop it now. + */ + if (mddev->pers->stop_resync) + mddev->pers->stop_resync(mddev); + if (mddev->recovery_running) + md_interrupt_thread(md_recovery_thread); + if (mddev->pers->error_handler) { + rc = mddev->pers->error_handler(mddev, rdev); + md_recover_arrays(); + return rc; + } + return 0; +} + +static int status_unused (char * page) +{ + int sz = 0, i = 0; + mdk_rdev_t *rdev; + struct md_list_head *tmp; + + sz += sprintf(page + sz, "unused devices: "); + + ITERATE_RDEV_ALL(rdev,tmp) { + if (!rdev->same_set.next && !rdev->same_set.prev) { + /* + * The device is not yet used by any array. + */ + i++; + sz += sprintf(page + sz, "%s ", + partition_name(rdev->dev)); } } + if (!i) + sz += sprintf(page + sz, ""); + + sz += sprintf(page + sz, "\n"); + return sz; } -EXPORT_SYMBOL(md_size); -EXPORT_SYMBOL(md_maxreadahead); -EXPORT_SYMBOL(register_md_personality); -EXPORT_SYMBOL(unregister_md_personality); -EXPORT_SYMBOL(md_dev); -EXPORT_SYMBOL(md_error); -EXPORT_SYMBOL(md_register_thread); -EXPORT_SYMBOL(md_unregister_thread); -EXPORT_SYMBOL(md_update_sb); -EXPORT_SYMBOL(md_map); -EXPORT_SYMBOL(md_wakeup_thread); -EXPORT_SYMBOL(md_do_sync); -#ifdef CONFIG_PROC_FS -static int md_status_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int status_resync (char * page, mddev_t * mddev) { - int sz = 0, i, j, size; - int begin = 0; + int sz = 0; + unsigned int blocksize, max_blocks, resync, res, dt, tt, et; + + resync = mddev->curr_resync; + blocksize = blksize_size[MD_MAJOR][mdidx(mddev)]; + max_blocks = blk_size[MD_MAJOR][mdidx(mddev)] / (blocksize >> 10); - sz=sprintf( page, "Personalities : "); - for (i=0; iname); - page[sz-1]='\n'; - - sz+=sprintf (page+sz, "read_ahead "); - if (read_ahead[MD_MAJOR]==INT_MAX) - sz+=sprintf (page+sz, "not set\n"); + /* + * Should not happen. + */ + if (!max_blocks) { + MD_BUG(); + return 0; + } + res = (resync/1024)*1000/(max_blocks/1024 + 1); + { + int i, x = res/50, y = 20-x; + sz += sprintf(page + sz, "["); + for (i = 0; i < x; i++) + sz += sprintf(page + sz, "="); + sz += sprintf(page + sz, ">"); + for (i = 0; i < y; i++) + sz += sprintf(page + sz, "."); + sz += sprintf(page + sz, "] "); + } + if (!mddev->recovery_running) + /* + * true resync + */ + sz += sprintf(page + sz, " resync =%3u.%u%% (%u/%u)", + res/10, res % 10, resync, max_blocks); else - sz+=sprintf (page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); + /* + * recovery ... + */ + sz += sprintf(page + sz, " recovery =%3u.%u%% (%u/%u)", + res/10, res % 10, resync, max_blocks); - for (i=0; i= off+count) { - *eof = 1; - break; - } - sz+=sprintf (page+sz, "md%d : %sactive", - i, md_dev[i].pers ? "" : "in"); + /* + * We do not want to overflow, so the order of operands and + * the * 100 / 100 trick are important. We do a +1 to be + * safe against division by zero. We only estimate anyway. + * + * dt: time until now + * tt: total time + * et: estimated finish time + */ + dt = ((jiffies - mddev->resync_start) / HZ); + tt = (dt * (max_blocks / (resync/100+1)))/100; + if (tt > dt) + et = tt - dt; + else + /* + * ignore rounding effects near finish time + */ + et = 0; + + sz += sprintf(page + sz, " finish=%u.%umin", et / 60, (et % 60)/6); - if (md_dev[i].pers) - sz+=sprintf (page+sz, " %s", md_dev[i].pers->name); + return sz; +} - for (j=0, size=0; jname); + + sz += sprintf(page+sz, "\n"); + + + sz += sprintf(page+sz, "read_ahead "); + if (read_ahead[MD_MAJOR] == INT_MAX) + sz += sprintf(page+sz, "not set\n"); + else + sz += sprintf(page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); + + ITERATE_MDDEV(mddev,tmp) { + sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev), + mddev->pers ? "" : "in"); + if (mddev->pers) { + if (mddev->ro) + sz += sprintf(page + sz, " (read-only)"); + sz += sprintf(page + sz, " %s", mddev->pers->name); + } + + size = 0; + ITERATE_RDEV(mddev,rdev,tmp2) { + sz += sprintf(page + sz, " %s[%d]", + partition_name(rdev->dev), rdev->desc_nr); + if (rdev->faulty) { + sz += sprintf(page + sz, "(F)"); + continue; + } + size += rdev->size; } - if (md_dev[i].nb_dev) { - if (md_dev[i].pers) - sz+=sprintf (page+sz, " %d blocks", md_size[i]); + if (mddev->nb_dev) { + if (mddev->pers) + sz += sprintf(page + sz, "\n %d blocks", + md_size[mdidx(mddev)]); else - sz+=sprintf (page+sz, " %d blocks", size); + sz += sprintf(page + sz, "\n %d blocks", size); } - if (!md_dev[i].pers) { - sz+=sprintf (page+sz, "\n"); + if (!mddev->pers) { + sz += sprintf(page+sz, "\n"); continue; } - if (md_dev[i].pers->max_invalid_dev) - sz+=sprintf (page+sz, " maxfault=%ld", - MAX_FAULT(md_dev+i)); + sz += mddev->pers->status (page+sz, mddev); - sz+=md_dev[i].pers->status (page+sz, i, md_dev+i); - sz+=sprintf (page+sz, "\n"); + sz += sprintf(page+sz, "\n "); + if (mddev->curr_resync) { + sz += status_resync (page+sz, mddev); + } else { + if (md_atomic_read(&mddev->resync_sem.count) != 1) + sz += sprintf(page + sz, " resync=DELAYED"); + } + sz += sprintf(page + sz, "\n"); } + sz += status_unused (page + sz); - sz -= off; - *start = page + off; - if (sz>count) - sz = count; - if (sz<0) - sz = 0; return sz; } -#endif - -static void md_geninit (void) -{ - int i; - - blksize_size[MD_MAJOR] = md_blocksizes; - max_readahead[MD_MAJOR] = md_maxreadahead; - for(i=0;i MAX_MD_DEV) - panic ("md_error gets unknown device\n"); - if (!md_dev [minor].pers) - panic ("md_error gets an error for an unknown device\n"); - if (md_dev [minor].pers->error_handler) { - rc = md_dev [minor].pers->error_handler (md_dev+minor, rdev); -#if SUPPORT_RECONSTRUCTION - md_wakeup_thread(md_sync_thread); -#endif /* SUPPORT_RECONSTRUCTION */ - return rc; - } - return 0; -} - -int register_md_personality (int p_num, struct md_personality *p) +int register_md_personality (int pnum, mdk_personality_t *p) { - int i=(p_num >> PERSONALITY_SHIFT); - - if (i >= MAX_PERSONALITY) - return -EINVAL; + if (pnum >= MAX_PERSONALITY) + return -EINVAL; - if (pers[i]) - return -EBUSY; + if (pers[pnum]) + return -EBUSY; - pers[i]=p; - printk ("%s personality registered\n", p->name); - return 0; + pers[pnum] = p; + printk(KERN_INFO "%s personality registered\n", p->name); + return 0; } -int unregister_md_personality (int p_num) +int unregister_md_personality (int pnum) { - int i=(p_num >> PERSONALITY_SHIFT); - - if (i >= MAX_PERSONALITY) - return -EINVAL; + if (pnum >= MAX_PERSONALITY) + return -EINVAL; - printk ("%s personality unregistered\n", pers[i]->name); - pers[i]=NULL; - return 0; + printk(KERN_INFO "%s personality unregistered\n", pers[pnum]->name); + pers[pnum] = NULL; + return 0; } -static md_descriptor_t *get_spare(struct md_dev *mddev) -{ - int i; - md_superblock_t *sb = mddev->sb; - md_descriptor_t *descriptor; - struct real_dev *realdev; - - for (i = 0; i < mddev->nb_dev; i++) { - realdev = &mddev->devices[i]; - if (!realdev->sb) - continue; - descriptor = &sb->disks[realdev->sb->descriptor.number]; - if (descriptor->state & (1 << MD_FAULTY_DEVICE)) - continue; - if (descriptor->state & (1 << MD_ACTIVE_DEVICE)) - continue; - return descriptor; - } - return NULL; -} - -/* - * parallel resyncing thread. - * - * FIXME: - make it abort with a dirty array on mdstop, now it just blocks - * - fix read error handing - */ - -int md_do_sync(struct md_dev *mddev) +int md_notify_reboot(struct notifier_block *this, + unsigned long code, void *x) { - struct buffer_head *bh; - int max_blocks, blocksize, curr_bsize, percent=1, j; - kdev_t read_disk = MKDEV(MD_MAJOR, mddev - md_dev); - int major = MAJOR(read_disk), minor = MINOR(read_disk); - unsigned long starttime; - - blocksize = blksize_size[major][minor]; - max_blocks = blk_size[major][minor] / (blocksize >> 10); - - printk("... resync log\n"); - printk(" .... mddev->nb_dev: %d\n", mddev->nb_dev); - printk(" .... raid array: %s\n", kdevname(read_disk)); - printk(" .... max_blocks: %d blocksize: %d\n", max_blocks, blocksize); - printk("md: syncing RAID array %s\n", kdevname(read_disk)); - - mddev->busy++; - - starttime=jiffies; - for (j = 0; j < max_blocks; j++) { - - /* - * B careful. When some1 mounts a non-'blocksize' filesystem - * then we get the blocksize changed right under us. Go deal - * with it transparently, recalculate 'blocksize', 'j' and - * 'max_blocks': - */ - curr_bsize = blksize_size[major][minor]; - if (curr_bsize != blocksize) { - diff_blocksize: - if (curr_bsize > blocksize) - /* - * this is safe, rounds downwards. - */ - j /= curr_bsize/blocksize; - else - j *= blocksize/curr_bsize; - - blocksize = curr_bsize; - max_blocks = blk_size[major][minor] / (blocksize >> 10); - } - if ((bh = breada (read_disk, j, blocksize, j * blocksize, - max_blocks * blocksize)) != NULL) { - mark_buffer_dirty(bh, 1); - brelse(bh); - } else { - /* - * FIXME: Ugly, but set_blocksize() isnt safe ... - */ - curr_bsize = blksize_size[major][minor]; - if (curr_bsize != blocksize) - goto diff_blocksize; + struct md_list_head *tmp; + mddev_t *mddev; - /* - * It's a real read problem. FIXME, handle this - * a better way. - */ - printk ( KERN_ALERT - "read error, stopping reconstruction.\n"); - mddev->busy--; - return 1; - } + if ((code == MD_SYS_DOWN) || (code == MD_SYS_HALT) + || (code == MD_SYS_POWER_OFF)) { - /* - * Let's sleep some if we are faster than our speed limit: - */ - while (blocksize*j/(jiffies-starttime+1)*HZ/1024 > SPEED_LIMIT) - { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } + printk(KERN_INFO "stopping all md devices.\n"); + ITERATE_MDDEV(mddev,tmp) + do_md_stop (mddev, 1); /* - * FIXME: put this status bar thing into /proc + * certain more exotic SCSI devices are known to be + * volatile wrt too early system reboots. While the + * right place to handle this issue is the given + * driver, we do want to have a safe RAID driver ... */ - if (!(j%(max_blocks/100))) { - if (!(percent%10)) - printk (" %03d%% done.\n",percent); - else - printk ("."); - percent++; - } + md_mdelay(1000*1); } - fsync_dev(read_disk); - printk("md: %s: sync done.\n", kdevname(read_disk)); - mddev->busy--; - return 0; + return NOTIFY_DONE; } -/* - * This is a kernel thread which: syncs a spare disk with the active array - * - * the amount of foolproofing might seem to be a tad excessive, but an - * early (not so error-safe) version of raid1syncd synced the first 0.5 gigs - * of my root partition with the first 0.5 gigs of my /home partition ... so - * i'm a bit nervous ;) - */ -void mdsyncd (void *data) +struct notifier_block md_notifier = { + md_notify_reboot, + NULL, + 0 +}; + +void md__init raid_setup(char *str, int *ints) { - int i; - struct md_dev *mddev; - md_superblock_t *sb; - md_descriptor_t *spare; - unsigned long flags; + char tmpline[100]; + int len, pos, nr, i; - for (i = 0, mddev = md_dev; i < MAX_MD_DEV; i++, mddev++) { - if ((sb = mddev->sb) == NULL) - continue; - if (sb->active_disks == sb->raid_disks) - continue; - if (!sb->spare_disks) - continue; - if ((spare = get_spare(mddev)) == NULL) - continue; - if (!mddev->pers->mark_spare) - continue; - if (mddev->pers->mark_spare(mddev, spare, SPARE_WRITE)) - continue; - if (md_do_sync(mddev) || (spare->state & (1 << MD_FAULTY_DEVICE))) { - mddev->pers->mark_spare(mddev, spare, SPARE_INACTIVE); + len = strlen(str) + 1; + nr = 0; + pos = 0; + + for (i = 0; i < len; i++) { + char c = str[i]; + + if (c == ',' || !c) { + tmpline[pos] = 0; + if (!strcmp(tmpline,"noautodetect")) + raid_setup_args.noautodetect = 1; + nr++; + pos = 0; continue; } - save_flags(flags); - cli(); - mddev->pers->mark_spare(mddev, spare, SPARE_ACTIVE); - spare->state |= (1 << MD_SYNC_DEVICE); - spare->state |= (1 << MD_ACTIVE_DEVICE); - sb->spare_disks--; - sb->active_disks++; - mddev->sb_dirty = 1; - md_update_sb(mddev - md_dev); - restore_flags(flags); + tmpline[pos] = c; + pos++; } - + raid_setup_args.set = 1; + return; } #ifdef CONFIG_MD_BOOT struct { unsigned long set; - int pers[MAX_MD_DEV]; - kdev_t devices[MAX_MD_DEV][MAX_REAL]; -} md_setup_args __initdata = { + int pers[MAX_MD_DEVS]; + kdev_t devices[MAX_MD_DEVS][MAX_REAL]; +} md_setup_args md__initdata = { 0,{0},{{0}} }; @@ -1155,7 +3207,7 @@ * the MD devices (by specifying multiple "md=" lines) * instead of just one. -- KTK */ -int __init md_setup(char *str) +static int __init md_setup(char *str) { int minor, level, factor, fault, i; kdev_t device; @@ -1167,31 +3219,31 @@ get_option(&str, &fault) != 2) { printk("md: Too few arguments supplied to md=.\n"); return 0; - } else if (minor >= MAX_MD_DEV) { - printk ("md: Minor device number too high.\n"); + } else if (minor >= MAX_MD_DEVS) { + printk ("md: Minor device number too high.\n"); return 0; } else if (md_setup_args.set & (1 << minor)) { printk ("md: Warning - md=%d,... has been specified twice;\n" " will discard the first definition.\n", minor); - } + } switch(level) { #ifdef CONFIG_MD_LINEAR case -1: level = LINEAR; pername = "linear"; - break; + break; #endif #ifdef CONFIG_MD_STRIPED case 0: level = STRIPED; pername = "striped"; - break; + break; #endif default: printk ("md: The kernel has not been configured for raid%d" " support!\n", level); return 0; - } + } devnames = str; for (i = 0; str; i++) { if ((device = name_to_kdev_t(str))) { @@ -1215,61 +3267,87 @@ md_setup_args.set |= (1 << minor); return 0; } - #endif +static void md_geninit (void) +{ + int i; + + blksize_size[MD_MAJOR] = md_blocksizes; + max_readahead[MD_MAJOR] = md_maxreadahead; + + for(i = 0; i < MAX_MD_DEVS; i++) { + md_blocksizes[i] = 1024; + md_maxreadahead[i] = MD_READAHEAD; + register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0); + + } + + printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); + +#ifdef CONFIG_PROC_FS + create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL); +#endif +} +void hsm_init (void); +void translucent_init (void); void linear_init (void); void raid0_init (void); void raid1_init (void); void raid5_init (void); -int __init md_init (void) +int md__init md_init (void) { - printk ("md driver %d.%d.%d MAX_MD_DEV=%d, MAX_REAL=%d\n", - MD_MAJOR_VERSION, MD_MINOR_VERSION, MD_PATCHLEVEL_VERSION, - MAX_MD_DEV, MAX_REAL); - - if (register_blkdev (MD_MAJOR, "md", &md_fops)) - { - printk ("Unable to get major %d for md\n", MD_MAJOR); - return (-1); - } - - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); - read_ahead[MD_MAJOR]=INT_MAX; - memset(md_dev, 0, MAX_MD_DEV * sizeof (struct md_dev)); - md_gendisk.next=gendisk_head; - - gendisk_head=&md_gendisk; - -#if SUPPORT_RECONSTRUCTION - if ((md_sync_thread = md_register_thread(mdsyncd, NULL)) == NULL) - printk("md: bug: md_sync_thread == NULL\n"); -#endif /* SUPPORT_RECONSTRUCTION */ + printk (KERN_INFO "md driver %d.%d.%d MAX_MD_DEVS=%d, MAX_REAL=%d\n", + MD_MAJOR_VERSION, MD_MINOR_VERSION, + MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MAX_REAL); + + if (register_blkdev (MD_MAJOR, "md", &md_fops)) + { + printk (KERN_ALERT "Unable to get major %d for md\n", MD_MAJOR); + return (-1); + } + + blk_dev[MD_MAJOR].queue = md_get_queue; + + read_ahead[MD_MAJOR] = INT_MAX; + md_gendisk.next = gendisk_head; + + gendisk_head = &md_gendisk; + + md_register_reboot_notifier(&md_notifier); #ifdef CONFIG_MD_LINEAR - linear_init (); + linear_init (); #endif #ifdef CONFIG_MD_STRIPED - raid0_init (); + raid0_init (); #endif #ifdef CONFIG_MD_MIRRORING - raid1_init (); + raid1_init (); #endif #ifdef CONFIG_MD_RAID5 - raid5_init (); + raid5_init (); #endif - md_geninit(); - return (0); +#if defined(CONFIG_MD_RAID5) || defined(CONFIG_MD_RAID5_MODULE) + /* + * pick a XOR routine, runtime. + */ + calibrate_xor_block(); +#endif + md_geninit(); + return (0); } #ifdef CONFIG_MD_BOOT -void __init md_setup_drive(void) +static void __init md_setup_drive(void) { + if(md_setup_args.set) + do_md_setup(md_setup_args.str, md_setup_args.ints); int minor, i; kdev_t dev; - for (minor = 0; minor < MAX_MD_DEV; minor++) { + for (minor = 0; minor < MAX_MD_DEVS; minor++) { if ((md_setup_args.set & (1 << minor)) == 0) continue; printk("md: Loading md%d.\n", minor); @@ -1281,3 +3359,20 @@ __setup("md=", md_setup); #endif + +MD_EXPORT_SYMBOL(md_size); +MD_EXPORT_SYMBOL(register_md_personality); +MD_EXPORT_SYMBOL(unregister_md_personality); +MD_EXPORT_SYMBOL(partition_name); +MD_EXPORT_SYMBOL(md_error); +MD_EXPORT_SYMBOL(md_recover_arrays); +MD_EXPORT_SYMBOL(md_register_thread); +MD_EXPORT_SYMBOL(md_unregister_thread); +MD_EXPORT_SYMBOL(md_update_sb); +MD_EXPORT_SYMBOL(md_wakeup_thread); +MD_EXPORT_SYMBOL(md_print_devices); +MD_EXPORT_SYMBOL(find_rdev_nr); +MD_EXPORT_SYMBOL(md_interrupt_thread); +MD_EXPORT_SYMBOL(mddev_map); +MD_EXPORT_SYMBOL(md_check_ordering); + diff -u --recursive --new-file v2.3.42/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c --- v2.3.42/linux/drivers/block/paride/pg.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/block/paride/pg.c Wed Feb 9 11:42:35 2000 @@ -260,18 +260,10 @@ /* kernel glue structures */ static struct file_operations pg_fops = { - NULL, /* lseek - default */ - pg_read, /* read */ - pg_write, /* write */ - NULL, /* readdir - bad */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - pg_open, /* open */ - NULL, /* flush */ - pg_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ + read: pg_read, + write: pg_write, + open: pg_open, + release: pg_release, }; void pg_init_units( void ) diff -u --recursive --new-file v2.3.42/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c --- v2.3.42/linux/drivers/block/paride/pt.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/block/paride/pt.c Wed Feb 9 11:42:35 2000 @@ -262,18 +262,11 @@ /* kernel glue structures */ static struct file_operations pt_fops = { - NULL, /* lseek - default */ - pt_read, /* read */ - pt_write, /* write */ - NULL, /* readdir - bad */ - NULL, /* select */ - pt_ioctl, /* ioctl */ - NULL, /* mmap */ - pt_open, /* open */ - NULL, /* flush */ - pt_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ + read: pt_read, + write: pt_write, + ioctl: pt_ioctl, + open: pt_open, + release: pt_release, }; void pt_init_units( void ) diff -u --recursive --new-file v2.3.42/linux/drivers/block/raid0.c linux/drivers/block/raid0.c --- v2.3.42/linux/drivers/block/raid0.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/raid0.c Tue Feb 8 11:39:00 2000 @@ -1,9 +1,10 @@ - /* raid0.c : Multiple Devices driver for Linux Copyright (C) 1994-96 Marc ZYNGIER or + Copyright (C) 1999, 2000 Ingo Molnar, Red Hat + RAID-0 management functions. @@ -18,146 +19,201 @@ */ #include -#include -#include -#include +#include #define MAJOR_NR MD_MAJOR #define MD_DRIVER #define MD_PERSONALITY -static int create_strip_zones (int minor, struct md_dev *mddev) +static int create_strip_zones (mddev_t *mddev) { - int i, j, c=0; - int current_offset=0; - struct real_dev *smallest_by_zone; - struct raid0_data *data=(struct raid0_data *) mddev->private; - - data->nr_strip_zones=1; - - for (i=1; inb_dev; i++) - { - for (j=0; jdevices[i].size==mddev->devices[j].size) - { - c=1; - break; - } - - if (!c) - data->nr_strip_zones++; - - c=0; - } - - if ((data->strip_zone=vmalloc(sizeof(struct strip_zone)*data->nr_strip_zones)) == NULL) - return 1; - - data->smallest=NULL; - - for (i=0; inr_strip_zones; i++) - { - data->strip_zone[i].dev_offset=current_offset; - smallest_by_zone=NULL; - c=0; - - for (j=0; jnb_dev; j++) - if (mddev->devices[j].size>current_offset) - { - data->strip_zone[i].dev[c++]=mddev->devices+j; - if (!smallest_by_zone || - smallest_by_zone->size > mddev->devices[j].size) - smallest_by_zone=mddev->devices+j; - } - - data->strip_zone[i].nb_dev=c; - data->strip_zone[i].size=(smallest_by_zone->size-current_offset)*c; - - if (!data->smallest || - data->smallest->size > data->strip_zone[i].size) - data->smallest=data->strip_zone+i; - - data->strip_zone[i].zone_offset=i ? (data->strip_zone[i-1].zone_offset+ - data->strip_zone[i-1].size) : 0; - current_offset=smallest_by_zone->size; - } - return 0; + int i, c, j, j1, j2; + int current_offset, curr_zone_offset; + raid0_conf_t *conf = mddev_to_conf(mddev); + mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; + + /* + * The number of 'same size groups' + */ + conf->nr_strip_zones = 0; + + ITERATE_RDEV_ORDERED(mddev,rdev1,j1) { + printk("raid0: looking at %s\n", partition_name(rdev1->dev)); + c = 0; + ITERATE_RDEV_ORDERED(mddev,rdev2,j2) { + printk("raid0: comparing %s(%d) with %s(%d)\n", partition_name(rdev1->dev), rdev1->size, partition_name(rdev2->dev), rdev2->size); + if (rdev2 == rdev1) { + printk("raid0: END\n"); + break; + } + if (rdev2->size == rdev1->size) + { + /* + * Not unique, dont count it as a new + * group + */ + printk("raid0: EQUAL\n"); + c = 1; + break; + } + printk("raid0: NOT EQUAL\n"); + } + if (!c) { + printk("raid0: ==> UNIQUE\n"); + conf->nr_strip_zones++; + printk("raid0: %d zones\n", conf->nr_strip_zones); + } + } + printk("raid0: FINAL %d zones\n", conf->nr_strip_zones); + + conf->strip_zone = vmalloc(sizeof(struct strip_zone)* + conf->nr_strip_zones); + if (!conf->strip_zone) + return 1; + + + conf->smallest = NULL; + current_offset = 0; + curr_zone_offset = 0; + + for (i = 0; i < conf->nr_strip_zones; i++) + { + struct strip_zone *zone = conf->strip_zone + i; + + printk("zone %d\n", i); + zone->dev_offset = current_offset; + smallest = NULL; + c = 0; + + ITERATE_RDEV_ORDERED(mddev,rdev,j) { + + printk(" checking %s ...", partition_name(rdev->dev)); + if (rdev->size > current_offset) + { + printk(" contained as device %d\n", c); + zone->dev[c] = rdev; + c++; + if (!smallest || (rdev->size size)) { + smallest = rdev; + printk(" (%d) is smallest!.\n", rdev->size); + } + } else + printk(" nope.\n"); + } + + zone->nb_dev = c; + zone->size = (smallest->size - current_offset) * c; + printk(" zone->nb_dev: %d, size: %d\n",zone->nb_dev,zone->size); + + if (!conf->smallest || (zone->size < conf->smallest->size)) + conf->smallest = zone; + + zone->zone_offset = curr_zone_offset; + curr_zone_offset += zone->size; + + current_offset = smallest->size; + printk("current zone offset: %d\n", current_offset); + } + printk("done.\n"); + return 0; } -static int raid0_run (int minor, struct md_dev *mddev) +static int raid0_run (mddev_t *mddev) { - int cur=0, i=0, size, zone0_size, nb_zone; - struct raid0_data *data; + int cur=0, i=0, size, zone0_size, nb_zone; + raid0_conf_t *conf; - MOD_INC_USE_COUNT; - - if ((mddev->private=vmalloc (sizeof (struct raid0_data))) == NULL) return 1; - data=(struct raid0_data *) mddev->private; - - if (create_strip_zones (minor, mddev)) - { - vfree(data); - return 1; - } - - nb_zone=data->nr_zones= - md_size[minor]/data->smallest->size + - (md_size[minor]%data->smallest->size ? 1 : 0); - - printk ("raid0 : Allocating %ld bytes for hash.\n",(long)sizeof(struct raid0_hash)*nb_zone); - if ((data->hash_table=vmalloc (sizeof (struct raid0_hash)*nb_zone)) == NULL) - { - vfree(data->strip_zone); - vfree(data); - return 1; - } - size=data->strip_zone[cur].size; - - i=0; - while (curnr_strip_zones) - { - data->hash_table[i].zone0=data->strip_zone+cur; - - if (size>=data->smallest->size)/* If we completely fill the slot */ - { - data->hash_table[i++].zone1=NULL; - size-=data->smallest->size; - - if (!size) - { - if (++cur==data->nr_strip_zones) continue; - size=data->strip_zone[cur].size; - } - - continue; - } - - if (++cur==data->nr_strip_zones) /* Last dev, set unit1 as NULL */ - { - data->hash_table[i].zone1=NULL; - continue; - } - - zone0_size=size; /* Here, we use a 2nd dev to fill the slot */ - size=data->strip_zone[cur].size; - data->hash_table[i++].zone1=data->strip_zone+cur; - size-=(data->smallest->size - zone0_size); - } + MOD_INC_USE_COUNT; - return (0); + conf = vmalloc(sizeof (raid0_conf_t)); + if (!conf) + goto out; + mddev->private = (void *)conf; + + if (md_check_ordering(mddev)) { + printk("raid0: disks are not ordered, aborting!\n"); + goto out_free_conf; + } + + if (create_strip_zones (mddev)) + goto out_free_conf; + + printk("raid0 : md_size is %d blocks.\n", md_size[mdidx(mddev)]); + printk("raid0 : conf->smallest->size is %d blocks.\n", conf->smallest->size); + nb_zone = md_size[mdidx(mddev)]/conf->smallest->size + + (md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0); + printk("raid0 : nb_zone is %d.\n", nb_zone); + conf->nr_zones = nb_zone; + + printk("raid0 : Allocating %d bytes for hash.\n", + sizeof(struct raid0_hash)*nb_zone); + + conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone); + if (!conf->hash_table) + goto out_free_zone_conf; + size = conf->strip_zone[cur].size; + + i = 0; + while (cur < conf->nr_strip_zones) { + conf->hash_table[i].zone0 = conf->strip_zone + cur; + + /* + * If we completely fill the slot + */ + if (size >= conf->smallest->size) { + conf->hash_table[i++].zone1 = NULL; + size -= conf->smallest->size; + + if (!size) { + if (++cur == conf->nr_strip_zones) + continue; + size = conf->strip_zone[cur].size; + } + continue; + } + if (++cur == conf->nr_strip_zones) { + /* + * Last dev, set unit1 as NULL + */ + conf->hash_table[i].zone1=NULL; + continue; + } + + /* + * Here we use a 2nd dev to fill the slot + */ + zone0_size = size; + size = conf->strip_zone[cur].size; + conf->hash_table[i++].zone1 = conf->strip_zone + cur; + size -= (conf->smallest->size - zone0_size); + } + return 0; + +out_free_zone_conf: + vfree(conf->strip_zone); + conf->strip_zone = NULL; + +out_free_conf: + vfree(conf); + mddev->private = NULL; +out: + MOD_DEC_USE_COUNT; + return 1; } - -static int raid0_stop (int minor, struct md_dev *mddev) +static int raid0_stop (mddev_t *mddev) { - struct raid0_data *data=(struct raid0_data *) mddev->private; + raid0_conf_t *conf = mddev_to_conf(mddev); - vfree (data->hash_table); - vfree (data->strip_zone); - vfree (data); + vfree (conf->hash_table); + conf->hash_table = NULL; + vfree (conf->strip_zone); + conf->strip_zone = NULL; + vfree (conf); + mddev->private = NULL; - MOD_DEC_USE_COUNT; - return 0; + MOD_DEC_USE_COUNT; + return 0; } /* @@ -167,135 +223,142 @@ * Of course, those facts may not be valid anymore (and surely won't...) * Hey guys, there's some work out there ;-) */ -static int raid0_map (struct md_dev *mddev, kdev_t *rdev, - unsigned long *rsector, unsigned long size) +static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) { - struct raid0_data *data=(struct raid0_data *) mddev->private; - static struct raid0_hash *hash; - struct strip_zone *zone; - struct real_dev *tmp_dev; - int blk_in_chunk, factor, chunk, chunk_size; - long block, rblock; - - factor=FACTOR(mddev); - chunk_size=(1UL << FACTOR_SHIFT(factor)); - block=*rsector >> 1; - hash=data->hash_table+(block/data->smallest->size); - - if (hash - data->hash_table > data->nr_zones) - { - printk(KERN_DEBUG "raid0_map: invalid block %ul\n", block); - return -1; - } - - /* Sanity check */ - if ((chunk_size*2)<(*rsector % (chunk_size*2))+size) - { - printk ("raid0_convert : can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, *rsector, size); - return (-1); - } - - if (block >= (hash->zone0->size + - hash->zone0->zone_offset)) - { - if (!hash->zone1) - { - printk ("raid0_convert : hash->zone1==NULL for block %ld\n", block); - return (-1); - } - - zone=hash->zone1; - } - else - zone=hash->zone0; + unsigned long size = bh->b_size >> 10; + raid0_conf_t *conf = mddev_to_conf(mddev); + struct raid0_hash *hash; + struct strip_zone *zone; + mdk_rdev_t *tmp_dev; + int blk_in_chunk, chunksize_bits, chunk, chunk_size; + long block, rblock; + + chunk_size = mddev->param.chunk_size >> 10; + chunksize_bits = ffz(~chunk_size); + block = bh->b_blocknr * size; + hash = conf->hash_table + block / conf->smallest->size; + + /* Sanity check */ + if (chunk_size < (block % chunk_size) + size) + goto bad_map; + + if (!hash) + goto bad_hash; + + if (!hash->zone0) + goto bad_zone0; + + if (block >= (hash->zone0->size + hash->zone0->zone_offset)) { + if (!hash->zone1) + goto bad_zone1; + zone = hash->zone1; + } else + zone = hash->zone0; - blk_in_chunk=block & (chunk_size -1); - chunk=(block - zone->zone_offset) / (zone->nb_dev<dev[(block >> FACTOR_SHIFT(factor)) % zone->nb_dev]; - rblock=(chunk << FACTOR_SHIFT(factor)) + blk_in_chunk + zone->dev_offset; - - *rdev=tmp_dev->dev; - *rsector=rblock<<1; - - return (0); + blk_in_chunk = block & (chunk_size -1); + chunk = (block - zone->zone_offset) / (zone->nb_dev << chunksize_bits); + tmp_dev = zone->dev[(block >> chunksize_bits) % zone->nb_dev]; + rblock = (chunk << chunksize_bits) + blk_in_chunk + zone->dev_offset; + + /* + * Important, at this point we are not guaranteed to be the only + * CPU modifying b_rdev and b_rsector! Only __make_request() later + * on serializes the IO. So in 2.4 we must never write temporary + * values to bh->b_rdev, like 2.2 and 2.0 did. + */ + bh->b_rdev = tmp_dev->dev; + bh->b_rsector = rblock << 1; + + generic_make_request(rw, bh); + + return 0; + +bad_map: + printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, bh->b_rsector, size); + return -1; +bad_hash: + printk("raid0_make_request bug: hash==NULL for block %ld\n", block); + return -1; +bad_zone0: + printk ("raid0_make_request bug: hash->zone0==NULL for block %ld\n", block); + return -1; +bad_zone1: + printk ("raid0_make_request bug: hash->zone1==NULL for block %ld\n", block); + return -1; } - -static int raid0_status (char *page, int minor, struct md_dev *mddev) +static int raid0_status (char *page, mddev_t *mddev) { - int sz=0; + int sz = 0; #undef MD_DEBUG #ifdef MD_DEBUG - int j, k; - struct raid0_data *data=(struct raid0_data *) mddev->private; + int j, k; + raid0_conf_t *conf = mddev_to_conf(mddev); - sz+=sprintf (page+sz, " "); - for (j=0; jnr_zones; j++) - { - sz+=sprintf (page+sz, "[z%d", - data->hash_table[j].zone0-data->strip_zone); - if (data->hash_table[j].zone1) - sz+=sprintf (page+sz, "/z%d] ", - data->hash_table[j].zone1-data->strip_zone); - else - sz+=sprintf (page+sz, "] "); - } + sz += sprintf(page + sz, " "); + for (j = 0; j < conf->nr_zones; j++) { + sz += sprintf(page + sz, "[z%d", + conf->hash_table[j].zone0 - conf->strip_zone); + if (conf->hash_table[j].zone1) + sz += sprintf(page+sz, "/z%d] ", + conf->hash_table[j].zone1 - conf->strip_zone); + else + sz += sprintf(page+sz, "] "); + } - sz+=sprintf (page+sz, "\n"); + sz += sprintf(page + sz, "\n"); - for (j=0; jnr_strip_zones; j++) - { - sz+=sprintf (page+sz, " z%d=[", j); - for (k=0; kstrip_zone[j].nb_dev; k++) - sz+=sprintf (page+sz, "%s/", - partition_name(data->strip_zone[j].dev[k]->dev)); - sz--; - sz+=sprintf (page+sz, "] zo=%d do=%d s=%d\n", - data->strip_zone[j].zone_offset, - data->strip_zone[j].dev_offset, - data->strip_zone[j].size); - } + for (j = 0; j < conf->nr_strip_zones; j++) { + sz += sprintf(page + sz, " z%d=[", j); + for (k = 0; k < conf->strip_zone[j].nb_dev; k++) + sz += sprintf (page+sz, "%s/", partition_name( + conf->strip_zone[j].dev[k]->dev)); + sz--; + sz += sprintf (page+sz, "] zo=%d do=%d s=%d\n", + conf->strip_zone[j].zone_offset, + conf->strip_zone[j].dev_offset, + conf->strip_zone[j].size); + } #endif - sz+=sprintf (page+sz, " %dk chunks", 1<param.chunk_size/1024); + return sz; } - -static struct md_personality raid0_personality= +static mdk_personality_t raid0_personality= { - "raid0", - raid0_map, - NULL, /* no special make_request */ - NULL, /* no special end_request */ - raid0_run, - raid0_stop, - raid0_status, - NULL, /* no ioctls */ - 0, - NULL, /* no error_handler */ - NULL, /* hot_add_disk */ - NULL, /* hot_remove_disk */ - NULL /* mark_spare */ + "raid0", + NULL, /* no special map */ + raid0_make_request, + NULL, /* no special end_request */ + raid0_run, + raid0_stop, + raid0_status, + NULL, /* no ioctls */ + 0, + NULL, /* no error_handler */ + NULL, /* no diskop */ + NULL, /* no stop resync */ + NULL /* no restart resync */ }; - #ifndef MODULE void raid0_init (void) { - register_md_personality (RAID0, &raid0_personality); + register_md_personality (RAID0, &raid0_personality); } #else int init_module (void) { - return (register_md_personality (RAID0, &raid0_personality)); + return (register_md_personality (RAID0, &raid0_personality)); } void cleanup_module (void) { - unregister_md_personality (RAID0); + unregister_md_personality (RAID0); } #endif + diff -u --recursive --new-file v2.3.42/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.3.42/linux/drivers/block/rd.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/rd.c Wed Feb 9 19:33:13 2000 @@ -270,7 +270,7 @@ } } if (rbh) { - set_bit(BH_Protected, &rbh->b_state); + mark_buffer_protected(rbh); brelse(rbh); } @@ -290,7 +290,10 @@ switch (cmd) { case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - invalidate_buffers(inode->i_rdev); + /* special: we want to release the ramdisk memory, + it's not like with the other blockdevices where + this ioctl only flushes away the buffer cache. */ + destroy_buffers(inode->i_rdev); break; case BLKGETSIZE: /* Return device size */ @@ -338,17 +341,8 @@ static struct file_operations initrd_fops = { - NULL, /* lseek */ - initrd_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* open */ - NULL, /* flush */ - initrd_release, /* release */ - NULL /* fsync */ + read: initrd_read, + release: initrd_release, }; #endif @@ -391,7 +385,7 @@ int i; for (i = 0 ; i < NUM_RAMDISKS; i++) - invalidate_buffers(MKDEV(MAJOR_NR, i)); + destroy_buffers(MKDEV(MAJOR_NR, i)); unregister_blkdev( MAJOR_NR, "ramdisk" ); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); diff -u --recursive --new-file v2.3.42/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v2.3.42/linux/drivers/cdrom/mcd.c Tue Dec 14 01:27:23 1999 +++ linux/drivers/cdrom/mcd.c Tue Feb 8 12:01:59 2000 @@ -1247,18 +1247,13 @@ if (result[1] == 'D') { - sprintf(msg, " mcd: Mitsumi Double Speed CD-ROM at port=0x%x," - " irq=%d\n", mcd_port, mcd_irq); MCMD_DATA_READ = MCMD_2X_READ; - - mcd_info.speed = 2; /* Added flag to drop to 1x speed if too many errors */ mcdDouble = 1; - } else { - sprintf(msg, " mcd: Mitsumi Single Speed CD-ROM at port=0x%x," - " irq=%d\n", mcd_port, mcd_irq); - mcd_info.speed = 2; - } + } else + mcd_info.speed = 1; + sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x," + " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double", mcd_port, mcd_irq); request_region(mcd_port, 4, "mcd"); diff -u --recursive --new-file v2.3.42/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.42/linux/drivers/char/Makefile Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/Makefile Mon Feb 7 09:51:43 2000 @@ -9,6 +9,18 @@ # parent makes.. # +O_OBJS := +OX_OBJS := +M_OBJS := +MX_OBJS := + +# Object file lists. + +obj-y := +obj-m := +obj-n := +obj- := + SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) ftape joystick pcmcia @@ -19,9 +31,13 @@ FONTMAPFILE = cp437.uni O_TARGET := char.o -M_OBJS := -O_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o raw.o -OX_OBJS := pty.o misc.o random.o +obj-y += tty_io.o n_tty.o tty_ioctl.o mem.o raw.o pty.o misc.o random.o + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := busmouse.o console.o i2c-old.o keyboard.o \ + misc.o pty.o random.o selection.o serial.o videodev.o KEYMAP =defkeymap.o KEYBD =pc_keyb.o @@ -44,195 +60,55 @@ SERIAL = endif -ifdef CONFIG_VT -O_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o -OX_OBJS += $(CONSOLE) selection.o -endif - -ifeq ($(CONFIG_SERIAL),y) -OX_OBJS += $(SERIAL) -else - ifeq ($(CONFIG_SERIAL),m) - MX_OBJS += $(SERIAL) - endif -endif - -ifeq ($(CONFIG_SERIAL_21285),y) -O_OBJS += serial_21285.o -endif +obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o +obj-$(CONFIG_SERIAL) += $(SERIAL) +obj-$(CONFIG_SERIAL_21285) += serial_21285.o ifndef CONFIG_SUN_KEYBOARD - ifdef CONFIG_VT - OX_OBJS += keyboard.o - O_OBJS += $(KEYMAP) $(KEYBD) - endif + obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) else - ifdef CONFIG_PCI - OX_OBJS += keyboard.o - O_OBJS += $(KEYMAP) - endif + obj-$(CONFIG_PCI) += keyboard.o $(KEYMAP) endif -ifdef CONFIG_MAGIC_SYSRQ -OX_OBJS += sysrq.o -endif +obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o +obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o ifeq ($(CONFIG_ATARI_DSP56K),y) -O_OBJS += dsp56k.o S = y else ifeq ($(CONFIG_ATARI_DSP56K),m) - M_OBJS += dsp56k.o SM = y endif endif -ifeq ($(CONFIG_ROCKETPORT),y) -O_OBJS += rocket.o -else - ifeq ($(CONFIG_ROCKETPORT),m) - M_OBJS += rocket.o - endif -endif - -ifeq ($(CONFIG_MOXA_SMARTIO),y) -L_OBJS += mxser.o -else - ifeq ($(CONFIG_MOXA_SMARTIO),m) - M_OBJS += mxser.o - endif -endif - -ifeq ($(CONFIG_MOXA_INTELLIO),y) -L_OBJS += moxa.o -else - ifeq ($(CONFIG_MOXA_INTELLIO),m) - M_OBJS += moxa.o - endif -endif - -ifeq ($(CONFIG_DIGI),y) -O_OBJS += pcxx.o -else - ifeq ($(CONFIG_DIGI),m) - M_OBJS += pcxx.o - endif -endif - -ifeq ($(CONFIG_DIGIEPCA),y) -O_OBJS += epca.o -else - ifeq ($(CONFIG_DIGIEPCA),m) - M_OBJS += epca.o - endif -endif - -ifeq ($(CONFIG_CYCLADES),y) -O_OBJS += cyclades.o -else - ifeq ($(CONFIG_CYCLADES),m) - M_OBJS += cyclades.o - endif -endif - -ifeq ($(CONFIG_STALLION),y) -O_OBJS += stallion.o -else - ifeq ($(CONFIG_STALLION),m) - M_OBJS += stallion.o - endif -endif - -ifeq ($(CONFIG_ISTALLION),y) -O_OBJS += istallion.o -else - ifeq ($(CONFIG_ISTALLION),m) - M_OBJS += istallion.o - endif -endif - -ifeq ($(CONFIG_COMPUTONE),y) -O_OBJS += ip2.o ip2main.o -else - ifeq ($(CONFIG_COMPUTONE),m) - M_OBJS += ip2.o ip2main.o - endif -endif - -ifeq ($(CONFIG_RISCOM8),y) -O_OBJS += riscom8.o -else - ifeq ($(CONFIG_RISCOM8),m) - M_OBJS += riscom8.o - endif -endif - -ifeq ($(CONFIG_ISI),y) -O_OBJS += isicom.o -else - ifeq ($(CONFIG_ISI),m) - M_OBJS += isicom.o - endif -endif - -ifeq ($(CONFIG_ESPSERIAL),y) -O_OBJS += esp.o -else - ifeq ($(CONFIG_ESPSERIAL),m) - M_OBJS += esp.o - endif -endif - -ifeq ($(CONFIG_SYNCLINK),m) - M_OBJS += synclink.o -endif - -ifeq ($(CONFIG_N_HDLC),m) - M_OBJS += n_hdlc.o -endif - -ifeq ($(CONFIG_SPECIALIX),y) -O_OBJS += specialix.o -else - ifeq ($(CONFIG_SPECIALIX),m) - M_OBJS += specialix.o - endif -endif +obj-$(CONFIG_ROCKETPORT) += rocket.o +obj-$(CONFIG_MOXA_SMARTIO) += mxser.o +obj-$(CONFIG_MOXA_INTELLIO) += moxa.o +obj-$(CONFIG_DIGI) += pcxx.o +obj-$(CONFIG_DIGIEPCA) += epca.o +obj-$(CONFIG_CYCLADES) += cyclades.o +obj-$(CONFIG_STALLION) += stallion.o +obj-$(CONFIG_ISTALLION) += istallion.o +obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o +obj-$(CONFIG_RISCOM8) += riscom8.o +obj-$(CONFIG_ISI) += isicom.o +obj-$(CONFIG_ESPSERIAL) += esp.o +obj-$(CONFIG_SYNCLINK) += synclink.o +obj-$(CONFIG_N_HDLC) += n_hdlc.o +obj-$(CONFIG_SPECIALIX) += specialix.o ifeq ($(CONFIG_SX),y) -O_OBJS += sx.o generic_serial.o -else - ifeq ($(CONFIG_SX),m) - M_OBJS += sx.o - endif -endif - -ifeq ($(CONFIG_ATIXL_BUSMOUSE),y) -O_OBJS += atixlmouse.o +obj-y += sx.o generic_serial.o else - ifeq ($(CONFIG_ATIXL_BUSMOUSE),m) - M_OBJS += atixlmouse.o - endif + obj-$(CONFIG_SX) += sx.o endif -ifeq ($(CONFIG_LOGIBUSMOUSE),y) -O_OBJS += logibusmouse.o -else - ifeq ($(CONFIG_LOGIBUSMOUSE),m) - M_OBJS += logibusmouse.o - endif -endif - -ifeq ($(CONFIG_PRINTER),y) -O_OBJS += lp.o -else - ifeq ($(CONFIG_PRINTER),m) - M_OBJS += lp.o - endif -endif +obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o +obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o +obj-$(CONFIG_PRINTER) += lp.o ifeq ($(CONFIG_JOYSTICK),y) -O_OBJS += joystick/js.o +obj-y += joystick/js.o SUB_DIRS += joystick MOD_SUB_DIRS += joystick else @@ -241,155 +117,35 @@ endif endif +obj-$(CONFIG_BUSMOUSE) += busmouse.o ifeq ($(CONFIG_BUSMOUSE),y) M = y -OX_OBJS += busmouse.o else ifeq ($(CONFIG_BUSMOUSE),m) MM = m - MX_OBJS += busmouse.o - endif -endif - -ifeq ($(CONFIG_DTLK),y) -O_OBJS += dtlk.o -else - ifeq ($(CONFIG_DTLK),m) - M_OBJS += dtlk.o - endif -endif - -ifeq ($(CONFIG_R3964),y) -O_OBJS += n_r3964.o -else - ifeq ($(CONFIG_R3964),m) - M_OBJS += n_r3964.o - endif -endif - -ifeq ($(CONFIG_APPLICOM),y) -O_OBJS += applicom.o -else - ifeq ($(CONFIG_APPLICOM),m) - M_OBJS += applicom.o - endif -endif - -ifeq ($(CONFIG_MS_BUSMOUSE),y) -O_OBJS += msbusmouse.o -else - ifeq ($(CONFIG_MS_BUSMOUSE),m) - M_OBJS += msbusmouse.o - endif -endif - -ifeq ($(CONFIG_82C710_MOUSE),y) -O_OBJS += qpmouse.o -else - ifeq ($(CONFIG_82C710_MOUSE),m) - M_OBJS += qpmouse.o - endif -endif - -ifeq ($(CONFIG_SOFT_WATCHDOG),y) -O_OBJS += softdog.o -else - ifeq ($(CONFIG_SOFT_WATCHDOG),m) - M_OBJS += softdog.o - endif -endif - -ifeq ($(CONFIG_PCWATCHDOG),y) -O_OBJS += pcwd.o -else - ifeq ($(CONFIG_PCWATCHDOG),m) - M_OBJS += pcwd.o - endif -endif - -ifeq ($(CONFIG_ACQUIRE_WDT),y) -O_OBJS += acquirewdt.o -else - ifeq ($(CONFIG_ACQUIRE_WDT),m) - M_OBJS += acquirewdt.o - endif -endif - -ifeq ($(CONFIG_MIXCOMWD),y) -O_OBJS += mixcomwd.o -else - ifeq ($(CONFIG_MIXCOMWD),m) - M_OBJS += mixcomwd.o - endif -endif - -ifeq ($(CONFIG_AMIGAMOUSE),y) -O_OBJS += amigamouse.o -else - ifeq ($(CONFIG_AMIGAMOUSE),m) - M_OBJS += amigamouse.o - endif -endif - -ifeq ($(CONFIG_ATARIMOUSE),y) -O_OBJS += atarimouse.o -else - ifeq ($(CONFIG_ATARIMOUSE),m) - M_OBJS += atarimouse.o - endif -endif - -ifeq ($(CONFIG_ADBMOUSE),y) -O_OBJS += adbmouse.o -else - ifeq ($(CONFIG_ADBMOUSE),m) - M_OBJS += adbmouse.o - endif -endif - -ifeq ($(CONFIG_PC110_PAD),y) -O_OBJS += pc110pad.o -else - ifeq ($(CONFIG_PC110_PAD),m) - M_OBJS += pc110pad.o endif endif -ifeq ($(CONFIG_WDT),y) -O_OBJS += wdt.o -else - ifeq ($(CONFIG_WDT),m) - M_OBJS += wdt.o - endif +obj-$(CONFIG_DTLK) += dtlk.o +obj-$(CONFIG_R3964) += n_r3964.o +obj-$(CONFIG_APPLICOM) += applicom.o +obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o +obj-$(CONFIG_82C710_MOUSE) += qpmouse.o +obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o +obj-$(CONFIG_PCWATCHDOG) += pcwd.o +obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o +obj-$(CONFIG_MIXCOMWD) += mixcomwd.o +obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o +obj-$(CONFIG_ATARIMOUSE) += atarimouse.o +obj-$(CONFIG_ADBMOUSE) += adbmouse.o +obj-$(CONFIG_PC110_PAD) += pc110pad.o +obj-$(CONFIG_WDT) += wdt.o +obj-$(CONFIG_RTC) += rtc.o +ifeq ($(CONFIG_PPC),) + obj-$(CONFIG_NVRAM) += nvram.o endif -ifeq ($(CONFIG_RTC),y) -O_OBJS += rtc.o -else - ifeq ($(CONFIG_RTC),m) - M_OBJS += rtc.o - endif -endif - -ifeq ($(CONFIG_NVRAM),y) - ifeq ($(CONFIG_PPC),) - O_OBJS += nvram.o - endif -else - ifeq ($(CONFIG_NVRAM),m) - ifeq ($(CONFIG_PPC),) - M_OBJS += nvram.o - endif - endif -endif - -ifeq ($(CONFIG_VIDEO_DEV),y) -OX_OBJS += videodev.o -else - ifeq ($(CONFIG_VIDEO_DEV),m) - MX_OBJS += videodev.o - endif -endif +obj-$(CONFIG_VIDEO_DEV) += videodev.o # # for external dependencies in arm/config.in and video/config.in @@ -398,222 +154,85 @@ L_I2C=y else ifeq ($(CONFIG_BUS_I2C),m) - M_I2C=y + L_I2C=m endif endif +obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o ifeq ($(CONFIG_VIDEO_BT848),y) -O_OBJS += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o L_I2C=y L_TUNERS=y else ifeq ($(CONFIG_VIDEO_BT848),m) - M_OBJS += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o - M_I2C=y - M_TUNERS=y + L_I2C=m + L_TUNERS=m endif endif +obj-$(CONFIG_VIDEO_ZR36120) += zoran.o ifeq ($(CONFIG_VIDEO_ZR36120),y) -O_OBJS += zoran.o L_I2C=y L_TUNERS=y L_DECODERS=y else ifeq ($(CONFIG_VIDEO_ZR36120),m) - M_OBJS += zoran.o - M_I2C=y - M_TUNERS=y - M_DECODERS=y + L_I2C=m + L_TUNERS=m + L_DECODERS=m endif endif +obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o ifeq ($(CONFIG_I2C_PARPORT),y) -O_OBJS += i2c-parport.o L_I2C = y else ifeq ($(CONFIG_I2C_PARPORT),m) - M_OBJS += i2c-parport.o M_I2C = y endif endif +obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o ifeq ($(CONFIG_VIDEO_SAA5249),y) -O_OBJS += saa5249.o L_I2C=y else ifeq ($(CONFIG_VIDEO_SAA5249),m) - M_OBJS += saa5249.o - M_I2C=y - endif -endif - -ifeq ($(CONFIG_VIDEO_CQCAM),y) -O_OBJS += c-qcam.o -else - ifeq ($(CONFIG_VIDEO_CQCAM),m) - M_OBJS += c-qcam.o - endif -endif - -ifeq ($(CONFIG_VIDEO_BWQCAM),y) -O_OBJS += bw-qcam.o -else - ifeq ($(CONFIG_VIDEO_BWQCAM),m) - M_OBJS += bw-qcam.o + L_I2C=m endif endif +obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o +obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o +obj-$(CONFIG_VIDEO_ZORAN) += buz.o ifeq ($(CONFIG_VIDEO_ZORAN),y) -O_OBJS += buz.o L_I2C=y L_DECODERS=y else ifeq ($(CONFIG_VIDEO_ZORAN),m) - M_OBJS += buz.o - M_I2C=y - M_DECODERS=y - endif -endif - -ifeq ($(CONFIG_VIDEO_LML33),y) -O_OBJS += bt856.o bt819.o -else - ifeq ($(CONFIG_VIDEO_LML33),m) - M_OBJS += bt856.o bt819.o - endif -endif - -ifeq ($(CONFIG_VIDEO_PMS),y) -O_OBJS += pms.o -else - ifeq ($(CONFIG_VIDEO_PMS),m) - M_OBJS += pms.o - endif -endif - -ifeq ($(CONFIG_VIDEO_PLANB),y) -O_OBJS += planb.o -else - ifeq ($(CONFIG_VIDEO_PLANB),m) - M_OBJS += planb.o - endif -endif - -ifeq ($(CONFIG_VIDEO_VINO),y) -O_OBJS += vino.o -else - ifeq ($(CONFIG_VIDEO_VINO),m) - M_OBJS += vino.o - endif -endif - -ifeq ($(CONFIG_VIDEO_STRADIS),y) -O_OBJS += vino.o -else - ifeq ($(CONFIG_VIDEO_STRADIS),m) - M_OBJS += stradis.o - endif -endif - -ifeq ($(CONFIG_RADIO_AZTECH),y) -O_OBJS += radio-aztech.o -else - ifeq ($(CONFIG_RADIO_AZTECH),m) - M_OBJS += radio-aztech.o - endif -endif - -ifeq ($(CONFIG_RADIO_RTRACK2),y) -O_OBJS += radio-rtrack2.o -else - ifeq ($(CONFIG_RADIO_RTRACK2),m) - M_OBJS += radio-rtrack2.o - endif -endif - -ifeq ($(CONFIG_RADIO_SF16FMI),y) -O_OBJS += radio-sf16fmi.o -else - ifeq ($(CONFIG_RADIO_SF16FMI),m) - M_OBJS += radio-sf16fmi.o - endif -endif - -ifeq ($(CONFIG_RADIO_CADET),y) -O_OBJS += radio-cadet.o -else - ifeq ($(CONFIG_RADIO_CADET),m) - M_OBJS += radio-cadet.o - endif -endif - -ifeq ($(CONFIG_RADIO_TYPHOON),y) -O_OBJS += radio-typhoon.o -else - ifeq ($(CONFIG_RADIO_TYPHOON),m) - M_OBJS += radio-typhoon.o + L_I2C=m + L_DECODERS=m endif endif -ifeq ($(CONFIG_RADIO_TERRATEC),y) -O_OBJS += radio-terratec.o -else - ifeq ($(CONFIG_RADIO_TERRATEC),m) - M_OBJS += radio-terratec.o - endif -endif - -ifeq ($(CONFIG_RADIO_RTRACK),y) -O_OBJS += radio-aimslab.o -else - ifeq ($(CONFIG_RADIO_RTRACK),m) - M_OBJS += radio-aimslab.o - endif -endif - -ifeq ($(CONFIG_RADIO_ZOLTRIX),y) -O_OBJS += radio-zoltrix.o -else - ifeq ($(CONFIG_RADIO_ZOLTRIX),m) - M_OBJS += radio-zoltrix.o - endif -endif - -ifeq ($(CONFIG_RADIO_MIROPCM20),y) -O_OBJS += radio-miropcm20.o -else - ifeq ($(CONFIG_RADIO_MIROPCM20),m) - M_OBJS += radio-miropcm20.o - endif -endif - -ifeq ($(CONFIG_RADIO_GEMTEK),y) -O_OBJS += radio-gemtek.o -else - ifeq ($(CONFIG_RADIO_GEMTEK),m) - M_OBJS += radio-gemtek.o - endif -endif - -ifeq ($(CONFIG_RADIO_TRUST),y) -O_OBJS += radio-trust.o -else - ifeq ($(CONFIG_RADIO_TRUST),m) - M_OBJS += radio-trust.o - endif -endif - -ifeq ($(CONFIG_QIC02_TAPE),y) -O_OBJS += tpqic02.o -else - ifeq ($(CONFIG_QIC02_TAPE),m) - M_OBJS += tpqic02.o - endif -endif +obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o +obj-$(CONFIG_VIDEO_PMS) += pms.o +obj-$(CONFIG_VIDEO_PLANB) += planb.o +obj-$(CONFIG_VIDEO_VINO) += vino.o +obj-$(CONFIG_VIDEO_STRADIS) += stradis.o +obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o +obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o +obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o +obj-$(CONFIG_RADIO_CADET) += radio-cadet.o +obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o +obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o +obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o +obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o +obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o +obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o +obj-$(CONFIG_RADIO_TRUST) += radio-trust.o +obj-$(CONFIG_QIC02_TAPE) += tpqic02.o ifeq ($(CONFIG_FTAPE),y) -O_OBJS += ftape/ftape.o +obj-y += ftape/ftape.o SUB_DIRS += ftape ifneq ($(CONFIG_ZFTAPE),n) MOD_SUB_DIRS += ftape @@ -624,45 +243,17 @@ endif endif -ifdef CONFIG_H8 -OX_OBJS += h8.o -endif - -ifeq ($(CONFIG_PPDEV),y) -O_OBJS += ppdev.o -else - ifeq ($(CONFIG_PPDEV),m) - M_OBJS += ppdev.o - endif -endif - +obj-$(CONFIG_H8) += h8.o +obj-$(CONFIG_PPDEV) += ppdev.o # set when a framegrabber supports external tuners -ifeq ($(L_TUNERS),y) -O_OBJS += tuner.o -else - ifeq ($(M_TUNERS),y) - M_OBJS += tuner.o - endif -endif +obj-$(L_TUNERS) += tuner.o # set when a framegrabber supports external decoders -ifeq ($(L_DECODERS),y) -O_OBJS += saa7110.o saa7111.o saa7185.o -else - ifeq ($(M_DECODERS),y) - M_OBJS += saa7110.o saa7111.o saa7185.o - endif -endif +obj-$(L_DECODERS) += saa7110.o saa7111.o saa7185.o # set when a framegrabber implements i2c support -ifeq ($(L_I2C),y) -OX_OBJS += i2c-old.o -else - ifeq ($(M_I2C),y) - MX_OBJS += i2c-old.o - endif -endif +obj-$(L_I2C) += i2c-old.o ifeq ($(CONFIG_DRM),y) SUB_DIRS += drm @@ -689,6 +280,30 @@ MOD_SUB_DIRS += agp endif endif + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +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 diff -u --recursive --new-file v2.3.42/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c --- v2.3.42/linux/drivers/char/acquirewdt.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/char/acquirewdt.c Wed Feb 9 11:42:35 2000 @@ -166,16 +166,11 @@ static struct file_operations acq_fops = { - NULL, - acq_read, - acq_write, - NULL, /* No Readdir */ - NULL, /* No Select */ - acq_ioctl, - NULL, /* No mmap */ - acq_open, - NULL, /* flush */ - acq_close + read: acq_read, + write: acq_write, + ioctl: acq_ioctl, + open: acq_open, + release: acq_close, }; static struct miscdevice acq_miscdev= diff -u --recursive --new-file v2.3.42/linux/drivers/char/agp/agp.h linux/drivers/char/agp/agp.h --- v2.3.42/linux/drivers/char/agp/agp.h Wed Dec 15 10:43:16 1999 +++ linux/drivers/char/agp/agp.h Thu Feb 10 12:22:03 2000 @@ -112,26 +112,6 @@ int (*remove_memory) (agp_memory *, off_t, int); agp_memory *(*alloc_by_type) (size_t, int); void (*free_by_type) (agp_memory *); - - /* Links to vendor/device specific setup functions */ -#ifdef CONFIG_AGP_INTEL - void (*intel_generic_setup) (void); -#endif -#ifdef CONFIG_AGP_I810 - void (*intel_i810_setup) (struct pci_dev *); -#endif -#ifdef CONFIG_AGP_VIA - void (*via_generic_setup) (void); -#endif -#ifdef CONFIG_AGP_SIS - void (*sis_generic_setup) (void); -#endif -#ifdef CONFIG_AGP_AMD - void (*amd_irongate_setup) (void); -#endif -#ifdef CONFIG_AGP_ALI - void (*ali_generic_setup) (void); -#endif }; #define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) @@ -156,6 +136,11 @@ #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) #endif + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define AGPGART_MODULE_NAME "agpgart" +#define PFX AGPGART_MODULE_NAME ": " #define PGE_EMPTY(p) (!(p) || (p) == (unsigned long) agp_bridge.scratch_page) diff -u --recursive --new-file v2.3.42/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.3.42/linux/drivers/char/agp/agpgart_be.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/char/agp/agpgart_be.c Thu Feb 10 12:22:03 2000 @@ -96,7 +96,7 @@ { atomic_set(&cpus_waiting, smp_num_cpus - 1); if (smp_call_function(ipi_handler, NULL, 1, 0) != 0) - panic("agpgart: timed out waiting for the other CPUs!\n"); + panic(PFX "timed out waiting for the other CPUs!\n"); flush_cache(); while (atomic_read(&cpus_waiting) > 0) barrier(); @@ -811,7 +811,7 @@ values = A_SIZE_FIX(agp_bridge.aperture_sizes); if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { - printk("agpgart: i810 is disabled\n"); + printk(KERN_WARNING PFX "i810 is disabled\n"); return 0; } if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { @@ -846,8 +846,7 @@ if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL) & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { /* This will need to be dynamically assigned */ - printk(KERN_INFO - "agpgart: detected 4MB dedicated video ram.\n"); + printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); intel_i810_private.num_dcache_entries = 1024; } pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); @@ -1024,7 +1023,7 @@ return addr | agp_bridge.masks[type].mask; } -static void intel_i810_setup(struct pci_dev *i810_dev) +static int __init intel_i810_setup(struct pci_dev *i810_dev) { intel_i810_private.i810_dev = i810_dev; @@ -1048,9 +1047,11 @@ agp_bridge.remove_memory = intel_i810_remove_entries; agp_bridge.alloc_by_type = intel_i810_alloc_by_type; agp_bridge.free_by_type = intel_i810_free_by_type; + + return 0; } -#endif +#endif /* CONFIG_AGP_I810 */ #ifdef CONFIG_AGP_INTEL @@ -1150,7 +1151,7 @@ {4, 1024, 0, 63} }; -static void intel_generic_setup(void) +static int __init intel_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = intel_generic_masks; agp_bridge.num_of_masks = 1; @@ -1172,9 +1173,13 @@ agp_bridge.remove_memory = agp_generic_remove_memory; agp_bridge.alloc_by_type = agp_generic_alloc_by_type; agp_bridge.free_by_type = agp_generic_free_by_type; + + return 0; + + (void) pdev; /* unused */ } -#endif +#endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_VIA @@ -1259,7 +1264,7 @@ {0x00000000, 0} }; -static void via_generic_setup(void) +static int __init via_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = via_generic_masks; agp_bridge.num_of_masks = 1; @@ -1281,9 +1286,13 @@ agp_bridge.remove_memory = agp_generic_remove_memory; agp_bridge.alloc_by_type = agp_generic_alloc_by_type; agp_bridge.free_by_type = agp_generic_free_by_type; + + return 0; + + (void) pdev; /* unused */ } -#endif +#endif /* CONFIG_AGP_VIA */ #ifdef CONFIG_AGP_SIS @@ -1364,7 +1373,7 @@ {0x00000000, 0} }; -static void sis_generic_setup(void) +static int __init sis_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = sis_generic_masks; agp_bridge.num_of_masks = 1; @@ -1386,9 +1395,13 @@ agp_bridge.remove_memory = agp_generic_remove_memory; agp_bridge.alloc_by_type = agp_generic_alloc_by_type; agp_bridge.free_by_type = agp_generic_free_by_type; + + return 0; + + (void) pdev; /* unused */ } -#endif +#endif /* CONFIG_AGP_SIS */ #ifdef CONFIG_AGP_AMD @@ -1523,7 +1536,7 @@ {0x00000001, 0} }; -static void amd_irongate_setup(void) +static int __init amd_irongate_setup (struct pci_dev *pdev) { agp_bridge.masks = amd_irongate_masks; agp_bridge.num_of_masks = 1; @@ -1545,9 +1558,13 @@ agp_bridge.remove_memory = agp_generic_remove_memory; agp_bridge.alloc_by_type = agp_generic_alloc_by_type; agp_bridge.free_by_type = agp_generic_free_by_type; + + return 0; + + (void) pdev; /* unused */ } -#endif +#endif /* CONFIG_AGP_AMD */ #ifdef CONFIG_AGP_ALI @@ -1645,7 +1662,7 @@ {4, 1024, 0, 3} }; -static void ali_generic_setup(void) +static int __init ali_generic_setup (struct pci_dev *pdev) { agp_bridge.masks = ali_generic_masks; agp_bridge.num_of_masks = 1; @@ -1667,24 +1684,188 @@ agp_bridge.remove_memory = agp_generic_remove_memory; agp_bridge.alloc_by_type = agp_generic_alloc_by_type; agp_bridge.free_by_type = agp_generic_free_by_type; + + return 0; + + (void) pdev; /* unused */ } -#endif +#endif /* CONFIG_AGP_ALI */ +/* per-chipset initialization data. + * note -- all chipsets for a single vendor MUST be grouped together + */ +static struct { + unsigned short device_id; /* first, to make table easier to read */ + unsigned short vendor_id; + enum chipset_type chipset; + const char *vendor_name; + const char *chipset_name; + int (*chipset_setup) (struct pci_dev *pdev); +} agp_bridge_info[] __initdata = { + +#ifdef CONFIG_AGP_ALI + { PCI_DEVICE_ID_AL_M1541_0, + PCI_VENDOR_ID_AL, + ALI_M1541, + "Ali", + "M1541", + ali_generic_setup }, + { 0, + PCI_VENDOR_ID_AL, + ALI_GENERIC, + "Ali", + "Generic", + ali_generic_setup }, +#endif /* CONFIG_AGP_ALI */ + +#ifdef CONFIG_AGP_AMD + { PCI_DEVICE_ID_AMD_IRONGATE_0, + PCI_VENDOR_ID_AMD, + AMD_IRONGATE, + "AMD", + "Irongate", + amd_irongate_setup }, + { 0, + PCI_VENDOR_ID_AMD, + AMD_GENERIC, + "AMD", + "Generic", + amd_irongate_setup }, +#endif /* CONFIG_AGP_AMD */ + +#ifdef CONFIG_AGP_INTEL + { PCI_DEVICE_ID_INTEL_82443LX_0, + PCI_VENDOR_ID_INTEL, + INTEL_LX, + "Intel", + "440LX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_82443BX_0, + PCI_VENDOR_ID_INTEL, + INTEL_BX, + "Intel", + "440BX", + intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_82443GX_0, + PCI_VENDOR_ID_INTEL, + INTEL_GX, + "Intel", + "440GX", + intel_generic_setup }, + { 0, + PCI_VENDOR_ID_INTEL, + INTEL_GENERIC, + "Intel", + "Generic", + intel_generic_setup }, +#endif /* CONFIG_AGP_INTEL */ + +#ifdef CONFIG_AGP_SIS + { 0, + PCI_VENDOR_ID_SI, + SIS_GENERIC, + "SiS", + "Generic", + sis_generic_setup }, +#endif /* CONFIG_AGP_SIS */ + +#ifdef CONFIG_AGP_VIA + { PCI_DEVICE_ID_VIA_8501_0, + PCI_VENDOR_ID_VIA, + VIA_MVP4, + "Via", + "MVP4", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C597_0, + PCI_VENDOR_ID_VIA, + VIA_VP3, + "Via", + "VP3", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C598_0, + PCI_VENDOR_ID_VIA, + VIA_MVP3, + "Via", + "MVP3", + via_generic_setup }, + { PCI_DEVICE_ID_VIA_82C691_0, + PCI_VENDOR_ID_VIA, + VIA_APOLLO_PRO, + "Via", + "Apollo Pro", + via_generic_setup }, + { 0, + PCI_VENDOR_ID_VIA, + VIA_GENERIC, + "Via", + "Generic", + via_generic_setup }, +#endif /* CONFIG_AGP_VIA */ + + { 0, }, /* dummy final entry, always present */ +}; + + +/* scan table above for supported devices */ +static int __init agp_lookup_host_bridge (struct pci_dev *pdev) +{ + int i; + + for (i = 0; i < arraysize (agp_bridge_info); i++) + if (pdev->vendor == agp_bridge_info[i].vendor_id) + break; + + if (i >= arraysize (agp_bridge_info)) { + printk (KERN_DEBUG PFX "unsupported bridge\n"); + return -ENODEV; + } + + while ((i < arraysize (agp_bridge_info)) && + (agp_bridge_info[i].vendor_id == pdev->vendor)) { + if (pdev->device == agp_bridge_info[i].device_id) { + printk (KERN_INFO PFX "Detected %s %s chipset\n", + agp_bridge_info[i].vendor_name, + agp_bridge_info[i].chipset_name); + agp_bridge.type = agp_bridge_info[i].chipset; + return agp_bridge_info[i].chipset_setup (pdev); + } + + i++; + } + + i--; /* point to vendor generic entry (device_id == 0) */ + + /* try init anyway, if user requests it AND + * there is a 'generic' bridge entry for this vendor */ + if (agp_try_unsupported && agp_bridge_info[i].device_id == 0) { + printk(KERN_WARNING PFX "Trying generic %s routines" + " for device id: %x\n", + agp_bridge_info[i].vendor_name, pdev->device); + agp_bridge.type = agp_bridge_info[i].chipset; + return agp_bridge_info[i].chipset_setup (pdev); + } + + printk(KERN_ERR PFX "Unsupported %s chipset," + " you might want to try " + "agp_try_unsupported=1.\n", + agp_bridge_info[i].vendor_name); + return -ENODEV; +} + /* Supported Device Scanning routine */ -static void agp_find_supported_device(void) +static int __init agp_find_supported_device(void) { struct pci_dev *dev = NULL; u8 cap_ptr = 0x00; u32 cap_id, scratch; - if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL) { - agp_bridge.type = NOT_SUPPORTED; - return; - } + if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL) + return -ENODEV; + agp_bridge.dev = dev; /* Need to test for I810 here */ @@ -1698,65 +1879,58 @@ PCI_DEVICE_ID_INTEL_810_1, NULL); if (i810_dev == NULL) { - printk("agpgart: Detected an Intel i810," + printk(KERN_ERR PFX "Detected an Intel i810," " but could not find the secondary" " device.\n"); - agp_bridge.type = NOT_SUPPORTED; - return; + return -ENODEV; } - printk(KERN_INFO "agpgart: Detected an Intel " + printk(KERN_INFO PFX "Detected an Intel " "i810 Chipset.\n"); agp_bridge.type = INTEL_I810; - agp_bridge.intel_i810_setup(i810_dev); - return; + return intel_i810_setup (i810_dev); case PCI_DEVICE_ID_INTEL_810_DC100_0: i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_810_DC100_1, NULL); if (i810_dev == NULL) { - printk("agpgart: Detected an Intel i810 " + printk(KERN_ERR PFX "Detected an Intel i810 " "DC100, but could not find the " "secondary device.\n"); - agp_bridge.type = NOT_SUPPORTED; - return; + return -ENODEV; } - printk(KERN_INFO "agpgart: Detected an Intel i810 " + printk(KERN_INFO PFX "Detected an Intel i810 " "DC100 Chipset.\n"); agp_bridge.type = INTEL_I810; - agp_bridge.intel_i810_setup(i810_dev); - return; + return intel_i810_setup(i810_dev); case PCI_DEVICE_ID_INTEL_810_E_0: i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_810_E_1, NULL); if (i810_dev == NULL) { - printk("agpgart: Detected an Intel i810 E" + printk(KERN_ERR PFX "Detected an Intel i810 E" ", but could not find the secondary " "device.\n"); - agp_bridge.type = NOT_SUPPORTED; - return; + return -ENODEV; } - printk(KERN_INFO "agpgart: Detected an Intel i810 E " + printk(KERN_INFO PFX "Detected an Intel i810 E " "Chipset.\n"); agp_bridge.type = INTEL_I810; - agp_bridge.intel_i810_setup(i810_dev); - return; + return intel_i810_setup(i810_dev); + default: break; } } -#endif +#endif /* CONFIG_AGP_I810 */ + /* find capndx */ pci_read_config_dword(dev, 0x04, &scratch); + if (!(scratch & 0x00100000)) + return -ENODEV; - if (!(scratch & 0x00100000)) { - agp_bridge.type = NOT_SUPPORTED; - return; - } pci_read_config_byte(dev, 0x34, &cap_ptr); - if (cap_ptr != 0x00) { do { pci_read_config_dword(dev, cap_ptr, &cap_id); @@ -1766,10 +1940,8 @@ } while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); } - if (cap_ptr == 0x00) { - agp_bridge.type = NOT_SUPPORTED; - return; - } + if (cap_ptr == 0x00) + return -ENODEV; agp_bridge.capndx = cap_ptr; /* Fill in the mode register */ @@ -1777,175 +1949,8 @@ agp_bridge.capndx + 4, &agp_bridge.mode); - switch (dev->vendor) { -#ifdef CONFIG_AGP_INTEL - case PCI_VENDOR_ID_INTEL: - switch (dev->device) { - case PCI_DEVICE_ID_INTEL_82443LX_0: - agp_bridge.type = INTEL_LX; - printk(KERN_INFO "agpgart: Detected an Intel 440LX" - " Chipset.\n"); - agp_bridge.intel_generic_setup(); - return; - - case PCI_DEVICE_ID_INTEL_82443BX_0: - agp_bridge.type = INTEL_BX; - printk(KERN_INFO "agpgart: Detected an Intel 440BX " - "Chipset.\n"); - agp_bridge.intel_generic_setup(); - return; - - case PCI_DEVICE_ID_INTEL_82443GX_0: - agp_bridge.type = INTEL_GX; - printk(KERN_INFO "agpgart: Detected an Intel 440GX " - "Chipset.\n"); - agp_bridge.intel_generic_setup(); - return; - - default: - if (agp_try_unsupported != 0) { - printk("agpgart: Trying generic intel " - "routines for device id: %x\n", - dev->device); - agp_bridge.type = INTEL_GENERIC; - agp_bridge.intel_generic_setup(); - return; - } else { - printk("agpgart: Unsupported intel chipset," - " you might want to try " - "agp_try_unsupported=1.\n"); - agp_bridge.type = NOT_SUPPORTED; - return; - } - } - break; -#endif - -#ifdef CONFIG_AGP_VIA - case PCI_VENDOR_ID_VIA: - switch (dev->device) { - case PCI_DEVICE_ID_VIA_82C597_0: - agp_bridge.type = VIA_VP3; - printk(KERN_INFO "agpgart: Detected a VIA VP3 " - "Chipset.\n"); - agp_bridge.via_generic_setup(); - return; - - case PCI_DEVICE_ID_VIA_82C598_0: - agp_bridge.type = VIA_MVP3; - printk(KERN_INFO "agpgart: Detected a VIA MVP3 " - "Chipset.\n"); - agp_bridge.via_generic_setup(); - return; - - case PCI_DEVICE_ID_VIA_82C691_0: - agp_bridge.type = VIA_APOLLO_PRO; - printk(KERN_INFO "agpgart: Detected a VIA Apollo " - "Pro Chipset.\n"); - agp_bridge.via_generic_setup(); - return; - - default: - if (agp_try_unsupported != 0) { - printk("agpgart: Trying generic VIA routines" - " for device id: %x\n", dev->device); - agp_bridge.type = VIA_GENERIC; - agp_bridge.via_generic_setup(); - return; - } else { - printk("agpgart: Unsupported VIA chipset," - " you might want to try " - "agp_try_unsupported=1.\n"); - agp_bridge.type = NOT_SUPPORTED; - return; - } - } - break; -#endif - -#ifdef CONFIG_AGP_SIS - case PCI_VENDOR_ID_SI: - switch (dev->device) { - /* ToDo need to find out the - * specific devices supported. - */ - default: - if (agp_try_unsupported != 0) { - printk("agpgart: Trying generic SiS routines" - " for device id: %x\n", dev->device); - agp_bridge.type = SIS_GENERIC; - agp_bridge.sis_generic_setup(); - return; - } else { - printk("agpgart: Unsupported SiS chipset, " - "you might want to try " - "agp_try_unsupported=1.\n"); - agp_bridge.type = NOT_SUPPORTED; - return; - } - } - break; -#endif - -#ifdef CONFIG_AGP_AMD - case PCI_VENDOR_ID_AMD: - switch (dev->device) { - case PCI_DEVICE_ID_AMD_IRONGATE_0: - agp_bridge.type = AMD_IRONGATE; - printk(KERN_INFO "agpgart: Detected an AMD Irongate" - " Chipset.\n"); - agp_bridge.amd_irongate_setup(); - return; - - default: - if (agp_try_unsupported != 0) { - printk("agpgart: Trying Amd irongate" - " routines for device id: %x\n", - dev->device); - agp_bridge.type = AMD_GENERIC; - agp_bridge.amd_irongate_setup(); - return; - } else { - printk("agpgart: Unsupported Amd chipset," - " you might want to try " - "agp_try_unsupported=1.\n"); - agp_bridge.type = NOT_SUPPORTED; - return; - } - } - break; -#endif - -#ifdef CONFIG_AGP_ALI - case PCI_VENDOR_ID_AL: - switch (dev->device) { - case PCI_DEVICE_ID_AL_M1541_0: - agp_bridge.type = ALI_M1541; - printk(KERN_INFO "agpgart: Detected an ALi M1541" - " Chipset\n"); - agp_bridge.ali_generic_setup(); - return; - default: - if (agp_try_unsupported != 0) { - printk("agpgart: Trying ALi generic routines" - " for device id: %x\n", dev->device); - agp_bridge.type = ALI_GENERIC; - agp_bridge.ali_generic_setup(); - return; - } else { - printk("agpgart: Unsupported ALi chipset," - " you might want to type " - "agp_try_unsupported=1.\n"); - agp_bridge.type = NOT_SUPPORTED; - return; - } - } - break; -#endif - default: - agp_bridge.type = NOT_SUPPORTED; - return; - } + /* probe for known chipsets */ + return agp_lookup_host_bridge (dev); } struct agp_max_table { @@ -1953,7 +1958,7 @@ int agp; }; -static struct agp_max_table maxes_table[9] = +static struct agp_max_table maxes_table[9] __initdata = { {0, 0}, {32, 4}, @@ -1966,7 +1971,7 @@ {4096, 3932} }; -static int agp_find_max(void) +static int __init agp_find_max (void) { long memory, index, result; @@ -1983,7 +1988,7 @@ (maxes_table[index].agp - maxes_table[index - 1].agp)) / (maxes_table[index].mem - maxes_table[index - 1].mem); - printk(KERN_INFO "agpgart: Maximum main memory to use " + printk(KERN_INFO PFX "Maximum main memory to use " "for agp memory: %ldM\n", result); result = result << (20 - PAGE_SHIFT); return result; @@ -1998,39 +2003,27 @@ AGPGART_VERSION_MINOR }; -static int agp_backend_initialize(void) +static int __init agp_backend_initialize(void) { - int size_value; + int size_value, rc, got_gatt=0, got_keylist=0; memset(&agp_bridge, 0, sizeof(struct agp_bridge_data)); agp_bridge.type = NOT_SUPPORTED; -#ifdef CONFIG_AGP_INTEL - agp_bridge.intel_generic_setup = intel_generic_setup; -#endif -#ifdef CONFIG_AGP_I810 - agp_bridge.intel_i810_setup = intel_i810_setup; -#endif -#ifdef CONFIG_AGP_VIA - agp_bridge.via_generic_setup = via_generic_setup; -#endif -#ifdef CONFIG_AGP_SIS - agp_bridge.sis_generic_setup = sis_generic_setup; -#endif -#ifdef CONFIG_AGP_AMD - agp_bridge.amd_irongate_setup = amd_irongate_setup; -#endif -#ifdef CONFIG_AGP_ALI - agp_bridge.ali_generic_setup = ali_generic_setup; -#endif agp_bridge.max_memory_agp = agp_find_max(); agp_bridge.version = &agp_current_version; - agp_find_supported_device(); + + rc = agp_find_supported_device(); + if (rc) { + /* not KERN_ERR because error msg should have already printed */ + printk(KERN_DEBUG PFX "no supported devices found.\n"); + return rc; + } if (agp_bridge.needs_scratch_page == TRUE) { agp_bridge.scratch_page = agp_alloc_page(); if (agp_bridge.scratch_page == 0) { - printk("agpgart: unable to get memory for " + printk(KERN_ERR PFX "unable to get memory for " "scratch page.\n"); return -ENOMEM; } @@ -2039,43 +2032,59 @@ agp_bridge.scratch_page = agp_bridge.mask_memory(agp_bridge.scratch_page, 0); } - if (agp_bridge.type == NOT_SUPPORTED) { - printk("agpgart: no supported devices found.\n"); - return -EINVAL; - } + size_value = agp_bridge.fetch_size(); if (size_value == 0) { - printk("agpgart: unable to detrimine aperture size.\n"); - return -EINVAL; + printk(KERN_ERR PFX "unable to detrimine aperture size.\n"); + rc = -EINVAL; + goto err_out; } if (agp_bridge.create_gatt_table()) { - printk("agpgart: unable to get memory for graphics " + printk(KERN_ERR PFX "unable to get memory for graphics " "translation table.\n"); - return -ENOMEM; + rc = -ENOMEM; + goto err_out; } + got_gatt = 1; + agp_bridge.key_list = vmalloc(PAGE_SIZE * 4); - if (agp_bridge.key_list == NULL) { - printk("agpgart: error allocating memory for key lists.\n"); - agp_bridge.free_gatt_table(); - return -ENOMEM; - } + printk(KERN_ERR PFX "error allocating memory for key lists.\n"); + rc = -ENOMEM; + goto err_out; + } + got_keylist = 1; + + /* FIXME vmalloc'd memory not guaranteed contiguous */ memset(agp_bridge.key_list, 0, PAGE_SIZE * 4); if (agp_bridge.configure()) { - printk("agpgart: error configuring host chipset.\n"); - agp_bridge.free_gatt_table(); - vfree(agp_bridge.key_list); - return -EINVAL; + printk(KERN_ERR PFX "error configuring host chipset.\n"); + rc = -EINVAL; + goto err_out; } - printk(KERN_INFO "agpgart: Physical address of the agp aperture:" - " 0x%lx\n", agp_bridge.gart_bus_addr); - printk(KERN_INFO "agpgart: Agp aperture is %dM in size.\n", - size_value); + + printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n", + size_value, agp_bridge.gart_bus_addr); + return 0; + +err_out: + if (agp_bridge.needs_scratch_page == TRUE) { + agp_bridge.scratch_page &= ~(0x00000fff); + agp_destroy_page((unsigned long) + phys_to_virt(agp_bridge.scratch_page)); + } + if (got_gatt) + agp_bridge.free_gatt_table(); + if (got_keylist) + vfree(agp_bridge.key_list); + return rc; } + +/* cannot be __exit b/c as it could be called from __init code */ static void agp_backend_cleanup(void) { agp_bridge.cleanup(); @@ -2098,17 +2107,17 @@ printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Jeff Hartmann\n", AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR); - ret_val = agp_backend_initialize(); - if (ret_val != 0) { + ret_val = agp_backend_initialize(); + if (ret_val) return ret_val; - } - ret_val = agp_frontend_initialize(); - if (ret_val != 0) { + ret_val = agp_frontend_initialize(); + if (ret_val) { agp_backend_cleanup(); return ret_val; } + return 0; } diff -u --recursive --new-file v2.3.42/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c --- v2.3.42/linux/drivers/char/agp/agpgart_fe.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/char/agp/agpgart_fe.c Thu Feb 10 12:41:51 2000 @@ -47,6 +47,8 @@ #include #include +#include "agp.h" + static struct agp_front_data agp_fe; static agp_memory *agp_find_mem_by_key(int key) @@ -298,7 +300,7 @@ agp_memory *memory; memory = agp_allocate_memory(pg_count, type); - printk("memory : %p\n", memory); + printk(KERN_DEBUG "memory : %p\n", memory); if (memory == NULL) { return NULL; } @@ -969,132 +971,123 @@ unsigned int cmd, unsigned long arg) { agp_file_private *curr_priv = (agp_file_private *) file->private_data; - int ret_val; + int ret_val = -ENOTTY; AGP_LOCK(); if ((agp_fe.current_controller == NULL) && (cmd != AGPIOC_ACQUIRE)) { - return -EINVAL; + ret_val = -EINVAL; + goto ioctl_out; } if ((agp_fe.backend_acquired != TRUE) && (cmd != AGPIOC_ACQUIRE)) { - return -EBUSY; + ret_val = -EBUSY; + goto ioctl_out; } if (cmd != AGPIOC_ACQUIRE) { if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { - return -EPERM; + ret_val = -EPERM; + goto ioctl_out; } /* Use the original pid of the controller, * in case it's threaded */ if (agp_fe.current_controller->pid != curr_priv->my_pid) { - return -EBUSY; + ret_val = -EBUSY; + goto ioctl_out; } } switch (cmd) { case AGPIOC_INFO: { ret_val = agpioc_info_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_ACQUIRE: { ret_val = agpioc_acquire_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_RELEASE: { ret_val = agpioc_release_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_SETUP: { ret_val = agpioc_setup_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_RESERVE: { ret_val = agpioc_reserve_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_PROTECT: { ret_val = agpioc_protect_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_ALLOCATE: { ret_val = agpioc_allocate_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_DEALLOCATE: { ret_val = agpioc_deallocate_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_BIND: { ret_val = agpioc_bind_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } case AGPIOC_UNBIND: { ret_val = agpioc_unbind_wrap(curr_priv, arg); - AGP_UNLOCK(); - return ret_val; + goto ioctl_out; } } - + +ioctl_out: AGP_UNLOCK(); - return -ENOTTY; + return ret_val; } static struct file_operations agp_fops = { - agp_lseek, - agp_read, - agp_write, - NULL, - NULL, - agp_ioctl, - agp_mmap, - agp_open, - NULL, - agp_release + llseek: agp_lseek, + read: agp_read, + write: agp_write, + ioctl: agp_ioctl, + mmap: agp_mmap, + open: agp_open, + release: agp_release, }; static struct miscdevice agp_miscdev = { AGPGART_MINOR, - "agpgart", + AGPGART_MODULE_NAME, &agp_fops }; -int agp_frontend_initialize(void) +int __init agp_frontend_initialize(void) { memset(&agp_fe, 0, sizeof(struct agp_front_data)); AGP_LOCK_INIT(); if (misc_register(&agp_miscdev)) { - printk("agpgart: unable to get minor: %d\n", AGPGART_MINOR); + printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR); return -EIO; } return 0; } -void agp_frontend_cleanup(void) +void __exit agp_frontend_cleanup(void) { misc_deregister(&agp_miscdev); - return; } diff -u --recursive --new-file v2.3.42/linux/drivers/char/applicom.c linux/drivers/char/applicom.c --- v2.3.42/linux/drivers/char/applicom.c Tue Sep 7 12:14:06 1999 +++ linux/drivers/char/applicom.c Wed Feb 9 11:42:35 2000 @@ -98,17 +98,12 @@ static void ac_interrupt(int irq, void *dev_instance, struct pt_regs *regs); struct file_operations ac_fops={ - ac_llseek, /* llseek */ - ac_read, /* read */ - ac_write, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - ac_ioctl, /* ioctl */ - NULL, /* mmap */ - ac_open, /* open */ - NULL, /* flush */ - ac_release, /* release */ - NULL /* fsync */ + llseek: ac_llseek, + read: ac_read, + write: ac_write, + ioctl: ac_ioctl, + open: ac_open, + release: ac_release, }; struct miscdevice ac_miscdev={ diff -u --recursive --new-file v2.3.42/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.3.42/linux/drivers/char/bttv.c Tue Jan 11 22:31:39 2000 +++ linux/drivers/char/bttv.c Wed Feb 9 18:48:03 2000 @@ -1765,6 +1765,14 @@ return count; } +static inline void burst(int on) +{ + tvnorms[0].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); + tvnorms[0].hdelayx1 = 186 - (on?BURSTOFFSET :0); + tvnorms[2].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); + tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0); +} + /* * Open a bttv card. Right now the flags stuff is just playing */ @@ -1775,6 +1783,7 @@ int i,ret; ret = -EBUSY; + down(&btv->lock); if (btv->user) goto out_unlock; @@ -1789,6 +1798,7 @@ for (i = 0; i < MAX_GBUFFERS; i++) btv->frame_stat[i] = GBUFFER_UNUSED; + burst(0); btv->user++; up(&btv->lock); MOD_INC_USE_COUNT; @@ -2454,19 +2464,13 @@ case BTTV_BURST_ON: { - tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2; - tvnorms[0].hdelayx1=186-BURSTOFFSET; - tvnorms[2].scaledtwidth=1135-BURSTOFFSET-2; - tvnorms[2].hdelayx1=186-BURSTOFFSET; + burst(1); return 0; } case BTTV_BURST_OFF: { - tvnorms[0].scaledtwidth=1135; - tvnorms[0].hdelayx1=186; - tvnorms[2].scaledtwidth=1135; - tvnorms[2].hdelayx1=186; + burst(0); return 0; } diff -u --recursive --new-file v2.3.42/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c --- v2.3.42/linux/drivers/char/busmouse.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/char/busmouse.c Wed Feb 9 11:42:35 2000 @@ -343,18 +343,12 @@ struct file_operations busmouse_fops= { - NULL, /* busmouse_seek */ - busmouse_read, - busmouse_write, - NULL, /* busmouse_readdir */ - busmouse_poll, - NULL, /* busmouse_ioctl */ - NULL, /* busmouse_mmap */ - busmouse_open, - NULL, /* busmouse_flush */ - busmouse_release, - NULL, - busmouse_fasync, + read: busmouse_read, + write: busmouse_write, + poll: busmouse_poll, + open: busmouse_open, + release: busmouse_release, + fasync: busmouse_fasync, }; int diff -u --recursive --new-file v2.3.42/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c --- v2.3.42/linux/drivers/char/dsp56k.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/char/dsp56k.c Wed Feb 9 11:42:35 2000 @@ -501,18 +501,11 @@ } static struct file_operations dsp56k_fops = { - NULL, /* no special dsp56k_lseek */ - dsp56k_read, - dsp56k_write, - NULL, /* no special dsp56k_readdir */ - NULL, /* dsp56k_poll? */ - dsp56k_ioctl, - NULL, /* no special dsp56k_mmap */ - dsp56k_open, - NULL, /* flush */ - dsp56k_release, - NULL, /* no special dsp56k_fsync */ - NULL, /* no special dsp56k_fasync */ + read: dsp56k_read, + write: dsp56k_write, + ioctl: dsp56k_ioctl, + open: dsp56k_open, + release: dsp56k_release, }; diff -u --recursive --new-file v2.3.42/linux/drivers/char/dtlk.c linux/drivers/char/dtlk.c --- v2.3.42/linux/drivers/char/dtlk.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/dtlk.c Wed Feb 9 11:42:35 2000 @@ -98,19 +98,12 @@ static struct file_operations dtlk_fops = { - NULL, /* lseek */ - dtlk_read, - dtlk_write, - NULL, /* readdir */ - dtlk_poll, - dtlk_ioctl, - NULL, /* mmap */ - dtlk_open, - NULL, /* flush */ - dtlk_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL /* lock */ + read: dtlk_read, + write: dtlk_write, + poll: dtlk_poll, + ioctl: dtlk_ioctl, + open: dtlk_open, + release: dtlk_release, }; /* local prototypes */ diff -u --recursive --new-file v2.3.42/linux/drivers/char/efirtc.c linux/drivers/char/efirtc.c --- v2.3.42/linux/drivers/char/efirtc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/efirtc.c Thu Feb 10 12:38:03 2000 @@ -0,0 +1,356 @@ +/* + * EFI Time Services Driver for Linux + * + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 Stephane Eranian + * + * Based on skeleton from the drivers/char/rtc.c driver by P. Gortmaker + * + * This code provides a architected & portable interface to the real time + * clock by using EFI instead of direct bit fiddling. The functionalities are + * quite different from the rtc.c driver. The only way to talk to the device + * is by using ioctl(). There is a /proc interface which provides the raw + * information. + * + * Please note that we have kept the API as close as possible from the + * legacy RTC. The standard /sbin/hwclock program should work normally + * when used to get/set the time. + * + * NOTES: + * - Locking is required for safe execution of EFI calls with regards + * to interrrupts and SMP. + * + * TODO (December 1999): + * - provide the API to set/get the WakeUp Alarm (different from the + * rtc.c alarm). + * - SMP testing + * - Add module support + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define EFI_RTC_VERSION "0.1" + +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) +/* + * EFI Epoch is 1/1/1998 + */ +#define EFI_RTC_EPOCH 1998 + +static spinlock_t efi_rtc_lock; + +static int efi_rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +#define is_leap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +static const unsigned short int __mon_yday[2][13] = +{ + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } +}; + +/* + * returns day of the year [0-365] + */ +static inline int +compute_yday(efi_time_t *eft) +{ + /* efi_time_t.month is in the [1-12] so, we need -1 */ + return __mon_yday[is_leap(eft->year)][eft->month-1]+ eft->day -1; +} +/* + * returns day of the week [0-6] 0=Sunday + * + * Don't try to provide a year that's before 1998, please ! + */ +static int +compute_wday(efi_time_t *eft) +{ + int y; + int ndays = 0; + + if ( eft->year < 1998 ) { + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n"); + return -1; + } + + for(y=EFI_RTC_EPOCH; y < eft->year; y++ ) { + ndays += 365 + (is_leap(y) ? 1 : 0); + } + ndays += compute_yday(eft); + + /* + * 4=1/1/1998 was a Thursday + */ + return (ndays + 4) % 7; +} + +static void +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft) +{ + + eft->year = wtime->tm_year + 1900; + eft->month = wtime->tm_mon + 1; + eft->day = wtime->tm_mday; + eft->hour = wtime->tm_hour; + eft->minute = wtime->tm_min; + eft->second = wtime->tm_sec; + eft->nanosecond = 0; + eft->daylight = wtime->tm_isdst ? EFI_ISDST: 0; + eft->timezone = EFI_UNSPECIFIED_TIMEZONE; +} + +static void +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime) +{ + wtime->tm_sec = eft->second; + wtime->tm_min = eft->minute; + wtime->tm_hour = eft->hour; + wtime->tm_mday = eft->day; + wtime->tm_mon = eft->month - 1; + wtime->tm_year = eft->year - 1900; + + /* day of the week [0-6], Sunday=0 */ + wtime->tm_wday = compute_wday(eft); + + /* day in the year [1-365]*/ + wtime->tm_yday = compute_yday(eft); + + + switch (eft->daylight & EFI_ISDST) { + case EFI_ISDST: + wtime->tm_isdst = 1; + break; + case EFI_TIME_ADJUST_DAYLIGHT: + wtime->tm_isdst = 0; + break; + default: + wtime->tm_isdst = -1; + } +} + +static int +efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + + efi_status_t status; + unsigned long flags; + efi_time_t eft; + efi_time_cap_t cap; + struct rtc_time wtime; + + switch (cmd) { + case RTC_UIE_ON: + case RTC_UIE_OFF: + case RTC_PIE_ON: + case RTC_PIE_OFF: + case RTC_AIE_ON: + case RTC_AIE_OFF: + case RTC_ALM_SET: + case RTC_ALM_READ: + case RTC_IRQP_READ: + case RTC_IRQP_SET: + case RTC_EPOCH_READ: + case RTC_EPOCH_SET: + return -EINVAL; + + case RTC_RD_TIME: + + spin_lock_irqsave(&efi_rtc_lock, flags); + + status = efi.get_time(&eft, &cap); + + spin_unlock_irqrestore(&efi_rtc_lock,flags); + + if (status != EFI_SUCCESS) { + /* should never happen */ + printk(KERN_ERR "efitime: can't read time\n"); + return -EINVAL; + } + + convert_from_efi_time(&eft, &wtime); + + return copy_to_user((void *)arg, &wtime, sizeof (struct rtc_time)) ? - EFAULT : 0; + + case RTC_SET_TIME: + + if (!capable(CAP_SYS_TIME)) return -EACCES; + + if (copy_from_user(&wtime, (struct rtc_time *)arg, sizeof(struct rtc_time)) ) + return -EFAULT; + + convert_to_efi_time(&wtime, &eft); + + spin_lock_irqsave(&efi_rtc_lock, flags); + + status = efi.set_time(&eft); + + spin_unlock_irqrestore(&efi_rtc_lock,flags); + + return status == EFI_SUCCESS ? 0 : -EINVAL; + } + return -EINVAL; +} + +/* + * We enforce only one user at a time here with the open/close. + * Also clear the previous interrupt data on an open, and clean + * up things on a close. + */ + +static int +efi_rtc_open(struct inode *inode, struct file *file) +{ + /* + * nothing special to do here + * We do accept multiple open files at the same time as we + * synchronize on the per call operation. + */ + return 0; +} + +static int +efi_rtc_close(struct inode *inode, struct file *file) +{ + return 0; +} + +/* + * The various file operations we support. + */ + +static struct file_operations efi_rtc_fops = { + ioctl: efi_rtc_ioctl, + open: efi_rtc_open, + release: efi_rtc_close, +}; + +static struct miscdevice efi_rtc_dev= +{ + EFI_RTC_MINOR, + "efirtc", + &efi_rtc_fops +}; + +/* + * We export RAW EFI information to /proc/efirtc + */ +static int +efi_rtc_get_status(char *buf) +{ + efi_time_t eft, alm; + efi_time_cap_t cap; + char *p = buf; + efi_bool_t enabled, pending; + unsigned long flags; + + spin_lock_irqsave(&efi_rtc_lock, flags); + + efi.get_time(&eft, &cap); + efi.get_wakeup_time(&enabled, &pending, &alm); + + spin_unlock_irqrestore(&efi_rtc_lock,flags); + + p += sprintf(p, + "Time :\n" + "Year : %u\n" + "Month : %u\n" + "Day : %u\n" + "Hour : %u\n" + "Minute : %u\n" + "Second : %u\n" + "Nanosecond: %u\n" + "Daylight : %u\n", + eft.year, eft.month, eft.day, eft.hour, eft.minute, + eft.second, eft.nanosecond, eft.daylight); + + if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE) + p += sprintf(p, "Timezone : unspecified\n"); + else + /* XXX fixme: convert to string? */ + p += sprintf(p, "Timezone : %u\n", eft.timezone); + + + p += sprintf(p, + "\nWakeup Alm:\n" + "Enabled : %s\n" + "Pending : %s\n" + "Year : %u\n" + "Month : %u\n" + "Day : %u\n" + "Hour : %u\n" + "Minute : %u\n" + "Second : %u\n" + "Nanosecond: %u\n" + "Daylight : %u\n", + enabled == 1 ? "Yes" : "No", + pending == 1 ? "Yes" : "No", + alm.year, alm.month, alm.day, alm.hour, alm.minute, + alm.second, alm.nanosecond, alm.daylight); + + if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE) + p += sprintf(p, "Timezone : unspecified\n"); + else + /* XXX fixme: convert to string? */ + p += sprintf(p, "Timezone : %u\n", eft.timezone); + + /* + * now prints the capabilities + */ + p += sprintf(p, + "\nClock Cap :\n" + "Resolution: %u\n" + "Accuracy : %u\n" + "SetstoZero: %u\n", + cap.resolution, cap.accuracy, cap.sets_to_zero); + + return p - buf; +} + +static int +efi_rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = efi_rtc_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; +} +static int __init +efi_rtc_init(void) +{ + printk(KERN_INFO "EFI Time Services Driver v%s\n", EFI_RTC_VERSION); + + misc_register(&efi_rtc_dev); + + create_proc_read_entry ("efirtc", 0, NULL, efi_rtc_read_proc, NULL); + + return 0; +} +static int __exit +efi_rtc_exit(void) +{ + /* not yet used */ + return 0; +} + +module_init(efi_rtc_init); +module_exit(efi_rtc_exit); diff -u --recursive --new-file v2.3.42/linux/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c --- v2.3.42/linux/drivers/char/ftape/zftape/zftape-init.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/char/ftape/zftape/zftape-init.c Wed Feb 9 11:42:35 2000 @@ -121,17 +121,12 @@ static struct file_operations zft_cdev = { - NULL, /* llseek */ - zft_read, /* read */ - zft_write, /* write */ - NULL, /* readdir */ - NULL, /* select */ - zft_ioctl, /* ioctl */ - zft_mmap, /* mmap */ - zft_open, /* open */ - NULL, /* flush */ - zft_close, /* release */ - NULL, /* fsync */ + read: zft_read, + write: zft_write, + ioctl: zft_ioctl, + mmap: zft_mmap, + open: zft_open, + release: zft_close, }; /* Open floppy tape device diff -u --recursive --new-file v2.3.42/linux/drivers/char/ip2main.c linux/drivers/char/ip2main.c --- v2.3.42/linux/drivers/char/ip2main.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/char/ip2main.c Wed Feb 9 11:42:35 2000 @@ -185,16 +185,11 @@ /* This is the driver descriptor for the ip2ipl device, which is used to * download the loadware to the boards. */ -static struct file_operations -ip2_ipl = { - NULL, - ip2_ipl_read, - ip2_ipl_write, - NULL, - NULL, - ip2_ipl_ioctl, - NULL, - ip2_ipl_open, +static struct file_operations ip2_ipl = { + read: ip2_ipl_read, + write: ip2_ipl_write, + ioctl: ip2_ipl_ioctl, + open: ip2_ipl_open, }; static long irq_counter = 0; diff -u --recursive --new-file v2.3.42/linux/drivers/char/isicom.c linux/drivers/char/isicom.c --- v2.3.42/linux/drivers/char/isicom.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/char/isicom.c Wed Feb 9 11:42:35 2000 @@ -109,18 +109,9 @@ */ static struct file_operations ISILoad_fops = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - ISILoad_ioctl, - NULL, /* mmap */ - ISILoad_open, - NULL, /* flush */ - ISILoad_release, - NULL, /* fsync */ - NULL, /* fasync */ + ioctl: ISILoad_ioctl, + open: ISILoad_open, + release: ISILoad_release, }; struct miscdevice isiloader_device = { diff -u --recursive --new-file v2.3.42/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.3.42/linux/drivers/char/istallion.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/char/istallion.c Wed Feb 9 11:42:35 2000 @@ -777,19 +777,11 @@ * board. This is also a very useful debugging tool. */ static struct file_operations stli_fsiomem = { - NULL, /* llseek */ - stli_memread, /* read */ - stli_memwrite, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - stli_memioctl, /* ioctl */ - NULL, /* mmap */ - stli_memopen, /* open */ - NULL, /* flush */ - stli_memclose, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - NULL /* lock */ + read: stli_memread, + write: stli_memwrite, + ioctl: stli_memioctl, + open: stli_memopen, + release: stli_memclose, }; /*****************************************************************************/ diff -u --recursive --new-file v2.3.42/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v2.3.42/linux/drivers/char/keyboard.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/keyboard.c Wed Feb 9 20:08:09 2000 @@ -898,7 +898,7 @@ * used, but this allows for easy and efficient race-condition * prevention later on. */ -static void kbd_bh(void) +static void kbd_bh(unsigned long dummy) { unsigned char leds = getleds(); @@ -909,6 +909,8 @@ } } +DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); + int __init kbd_init(void) { int i; @@ -928,8 +930,9 @@ ttytab = console_driver.table; kbd_init_hw(); - init_bh(KEYBOARD_BH, kbd_bh); - mark_bh(KEYBOARD_BH); + + tasklet_enable(&keyboard_tasklet); + tasklet_schedule(&keyboard_tasklet); pm_kbd = pm_register(PM_SYS_DEV, PM_SYS_KBC, NULL); diff -u --recursive --new-file v2.3.42/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.3.42/linux/drivers/char/lp.c Tue Jan 4 13:57:16 2000 +++ linux/drivers/char/lp.c Wed Feb 9 11:42:35 2000 @@ -106,6 +106,8 @@ * month ago... * * 14 Dec 1998, Andrea Arcangeli + * + * Copyright (C) 2000 by Tim Waugh (added LPSETTIMEOUT ioctl) */ #include @@ -133,6 +135,9 @@ /* if you have more than 3 printers, remember to increase LP_NO */ #define LP_NO 3 +/* ROUND_UP macro from fs/select.c */ +#define ROUND_UP(x,y) (((x)+(y)-1)/(y)) + struct lp_struct lp_table[LP_NO]; static unsigned int lp_count = 0; @@ -321,6 +326,7 @@ ssize_t retv = 0; ssize_t written; size_t copy_size = count; + long old_to; #ifdef LP_STATS if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) @@ -346,6 +352,9 @@ /* Go to compatibility mode. */ parport_negotiate (port, IEEE1284_MODE_COMPAT); + old_to = parport_set_timeout (lp_table[minor].dev, + lp_table[minor].timeout); + do { /* Write the data. */ written = parport_write (port, kbuf, copy_size); @@ -390,6 +399,9 @@ } } while (count > 0); + /* Not really necessary, but polite. */ + parport_set_timeout (lp_table[minor].dev, old_to); + lp_parport_release (minor); up (&lp_table[minor].port_mutex); @@ -527,6 +539,9 @@ if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV; switch ( cmd ) { + struct timeval par_timeout; + long to_jiffies; + case LPTIME: LP_TIME(minor) = arg * HZ/100; break; @@ -588,6 +603,26 @@ if (copy_to_user((int *) arg, &status, sizeof(int))) return -EFAULT; break; + + case LPSETTIMEOUT: + if (copy_from_user (&par_timeout, + (struct timeval *) arg, + sizeof (struct timeval))) { + return -EFAULT; + } + /* Convert to jiffies, place in lp_table */ + if ((par_timeout.tv_sec < 0) || + (par_timeout.tv_usec < 0)) { + return -EINVAL; + } + to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ); + to_jiffies += par_timeout.tv_sec * (long) HZ; + if (to_jiffies <= 0) { + return -EINVAL; + } + lp_table[minor].timeout = to_jiffies; + break; + default: retval = -EINVAL; } @@ -610,24 +645,14 @@ #endif /* IEEE 1284 support */ static struct file_operations lp_fops = { - lp_lseek, -#ifdef CONFIG_PARPORT_1284 - lp_read, -#else - NULL, -#endif - lp_write, - NULL, /* lp_readdir */ + write: lp_write, + ioctl: lp_ioctl, + open: lp_open, + release: lp_release, #ifdef CONFIG_PARPORT_1284 - lp_poll, -#else - NULL, + read: lp_read, + poll: lp_poll, #endif - lp_ioctl, - NULL, /* lp_mmap */ - lp_open, - NULL, /* flush */ - lp_release }; /* --- support for console on the line printer ----------------- */ @@ -664,28 +689,33 @@ do { /* Write the data, converting LF->CRLF as we go. */ ssize_t canwrite = count; - char *line = strchr (s, '\n'); - if (line) - canwrite = line - s; - - written = parport_write (port, s, canwrite); - if (written <= 0) - continue; - - s += written; - count -= written; - if (line) { + char *lf = strchr (s, '\n'); + if (lf) + canwrite = lf - s; + + if (canwrite > 0) { + written = parport_write (port, s, canwrite); + + if (written <= 0) + continue; + + s += written; + count -= written; + canwrite -= written; + } + + if (lf && canwrite <= 0) { const char *crlf = "\r\n"; int i = 2; /* Dodge the original '\n', and put '\r\n' instead. */ s++; count--; - while (i) { + do { written = parport_write (port, crlf, i); if (written > 0) i -= written, crlf += written; - } + } while (i > 0 && (CONSOLE_LP_STRICT || written > 0)); } } while (count > 0 && (CONSOLE_LP_STRICT || written > 0)); @@ -698,7 +728,7 @@ } static struct console lpcons = { - "lp0", + "lp", lp_console_write, NULL, lp_console_device, @@ -706,7 +736,7 @@ NULL, NULL, CON_PRINTBUFFER, - -1, + 0, 0, NULL }; @@ -778,6 +808,7 @@ #ifdef CONFIG_LP_CONSOLE if (!nr) { if (port->modes & PARPORT_MODE_SAFEININT) { + MOD_INC_USE_COUNT; register_console (&lpcons); printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP); } else @@ -854,6 +885,7 @@ init_waitqueue_head (&lp_table[i].waitq); init_waitqueue_head (&lp_table[i].dataq); init_MUTEX (&lp_table[i].port_mutex); + lp_table[i].timeout = 10 * HZ; } if (register_chrdev (LP_MAJOR, "lp", &lp_fops)) { diff -u --recursive --new-file v2.3.42/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.3.42/linux/drivers/char/mem.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/mem.c Wed Feb 9 18:48:03 2000 @@ -145,11 +145,15 @@ return do_write_mem(file, __va(p), p, buf, count, ppos); } +#ifndef pgprot_noncached + /* * This should probably be per-architecture in */ -static inline unsigned long pgprot_noncached(unsigned long prot) +static inline pgprot_t pgprot_noncached(pgprot_t _prot) { + unsigned long prot = pgprot_val(_prot); + #if defined(__i386__) /* On PPro and successors, PCD alone doesn't always mean uncached because of interactions with the MTRRs. PCD | PWT @@ -173,9 +177,11 @@ prot &= ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE); #endif - return prot; + return __pgprot(prot); } +#endif /* !pgprot_noncached */ + /* * Architectures vary in how they handle caching for addresses * outside of main memory. @@ -208,8 +214,7 @@ * done non-cached. */ if (noncached_address(offset) || (file->f_flags & O_SYNC)) - pgprot_val(vma->vm_page_prot) - = pgprot_noncached(pgprot_val(vma->vm_page_prot)); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* * Don't dump addresses that are not real memory to a core file. @@ -486,87 +491,47 @@ #define open_kmem open_mem static struct file_operations mem_fops = { - memory_lseek, - read_mem, - write_mem, - NULL, /* mem_readdir */ - NULL, /* mem_poll */ - NULL, /* mem_ioctl */ - mmap_mem, - open_mem, - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* fsync */ + llseek: memory_lseek, + read: read_mem, + write: write_mem, + mmap: mmap_mem, + open: open_mem, }; static struct file_operations kmem_fops = { - memory_lseek, - read_kmem, - write_kmem, - NULL, /* kmem_readdir */ - NULL, /* kmem_poll */ - NULL, /* kmem_ioctl */ - mmap_kmem, - open_kmem, - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* fsync */ + llseek: memory_lseek, + read: read_kmem, + write: write_kmem, + mmap: mmap_kmem, + open: open_kmem, }; static struct file_operations null_fops = { - null_lseek, - read_null, - write_null, - NULL, /* null_readdir */ - NULL, /* null_poll */ - NULL, /* null_ioctl */ - NULL, /* null_mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* fsync */ + llseek: null_lseek, + read: read_null, + write: write_null, }; #if !defined(CONFIG_PPC) && !defined(__mc68000__) static struct file_operations port_fops = { - memory_lseek, - read_port, - write_port, - NULL, /* port_readdir */ - NULL, /* port_poll */ - NULL, /* port_ioctl */ - NULL, /* port_mmap */ - open_port, - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* fsync */ + llseek: memory_lseek, + read: read_port, + write: write_port, + open: open_port, }; #endif static struct file_operations zero_fops = { - zero_lseek, - read_zero, - write_zero, - NULL, /* zero_readdir */ - NULL, /* zero_poll */ - NULL, /* zero_ioctl */ - mmap_zero, - NULL, /* no special open code */ - NULL, /* flush */ - NULL /* no special release code */ + llseek: zero_lseek, + read: read_zero, + write: write_zero, + mmap: mmap_zero, }; static struct file_operations full_fops = { - full_lseek, - read_full, - write_full, - NULL, /* full_readdir */ - NULL, /* full_poll */ - NULL, /* full_ioctl */ - NULL, /* full_mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL /* no special release code */ + llseek: full_lseek, + read: read_full, + write: write_full, }; static int memory_open(struct inode * inode, struct file * filp) @@ -607,17 +572,7 @@ } static struct file_operations memory_fops = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - memory_open, /* just a selector for the real open */ - NULL, /* flush */ - NULL, /* release */ - NULL /* fsync */ + open: memory_open, /* just a selector for the real open */ }; int __init chr_dev_init(void) @@ -630,7 +585,7 @@ usb_init(); #endif #ifdef CONFIG_I2C - i2c_init_all(); + i2c_init_all(); #endif #if defined (CONFIG_FB) fbmem_init(); diff -u --recursive --new-file v2.3.42/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.3.42/linux/drivers/char/misc.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/misc.c Wed Feb 9 11:42:35 2000 @@ -116,16 +116,7 @@ } static struct file_operations misc_fops = { - NULL, /* seek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - misc_open, - NULL, /* flush */ - NULL /* release */ + open: misc_open, }; int misc_register(struct miscdevice * misc) diff -u --recursive --new-file v2.3.42/linux/drivers/char/mixcomwd.c linux/drivers/char/mixcomwd.c --- v2.3.42/linux/drivers/char/mixcomwd.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/mixcomwd.c Wed Feb 9 11:42:35 2000 @@ -166,18 +166,10 @@ static struct file_operations mixcomwd_fops= { - NULL, /* Seek */ - NULL, /* Read */ - mixcomwd_write, /* Write */ - NULL, /* Readdir */ - NULL, /* Select */ - mixcomwd_ioctl, /* Ioctl */ - NULL, /* MMap */ - mixcomwd_open, - NULL, /* flush */ - mixcomwd_release, - NULL, - NULL /* Fasync */ + write: mixcomwd_write, + ioctl: mixcomwd_ioctl, + open: mixcomwd_open, + release: mixcomwd_release, }; static struct miscdevice mixcomwd_miscdev= diff -u --recursive --new-file v2.3.42/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.3.42/linux/drivers/char/msp3400.c Tue Jan 11 22:31:40 2000 +++ linux/drivers/char/msp3400.c Wed Feb 9 11:42:35 2000 @@ -1274,19 +1274,10 @@ } static struct file_operations msp3400c_mixer_fops = { - msp3400c_mixer_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - msp3400c_mixer_ioctl, - NULL, /* mmap */ - msp3400c_mixer_open, - NULL, - msp3400c_mixer_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: msp3400c_mixer_llseek, + ioctl: msp3400c_mixer_ioctl, + open: msp3400c_mixer_open, + release: msp3400c_mixer_release, }; #endif diff -u --recursive --new-file v2.3.42/linux/drivers/char/nvram.c linux/drivers/char/nvram.c --- v2.3.42/linux/drivers/char/nvram.c Mon Nov 1 13:56:26 1999 +++ linux/drivers/char/nvram.c Wed Feb 9 11:42:35 2000 @@ -393,16 +393,12 @@ #endif /* CONFIG_PROC_FS */ static struct file_operations nvram_fops = { - nvram_llseek, - nvram_read, - nvram_write, - NULL, /* No readdir */ - NULL, /* No poll */ - nvram_ioctl, - NULL, /* No mmap */ - nvram_open, - NULL, /* flush */ - nvram_release + llseek: nvram_llseek, + read: nvram_read, + write: nvram_write, + ioctl: nvram_ioctl, + open: nvram_open, + release: nvram_release, }; static struct miscdevice nvram_dev = { diff -u --recursive --new-file v2.3.42/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c --- v2.3.42/linux/drivers/char/pc110pad.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/char/pc110pad.c Thu Feb 10 12:29:58 2000 @@ -1,5 +1,9 @@ /* * Linux driver for the PC110 pad + */ + +/** + * DOC: PC110 Digitizer Hardware * * The pad provides triples of data. The first byte has * 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down @@ -7,13 +11,24 @@ * The third is bits 0-6 Y * * This is read internally and used to synthesize a stream of - * triples in the form expected from a PS/2 device. + * triples in the form expected from a PS/2 device. Specialist + * applications can choose to obtain the pad data in other formats + * including a debugging mode. + * + * It would be good to add a joystick driver mode to this pad so + * that doom and other game playing are better. One possible approach + * would be to deactive the mouse mode while the joystick port is opened. + */ + +/* + * History * * 0.0 1997-05-16 Alan Cox - Pad reader * 0.1 1997-05-19 Robin O'Leary - PS/2 emulation * 0.2 1997-06-03 Robin O'Leary - tap gesture * 0.3 1997-06-27 Alan Cox - 2.1 commit * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes + * 0.5 2000-02-10 Alan Cox - 2.3.x cleanup, documentation */ #include @@ -56,7 +71,9 @@ static struct semaphore reader_lock; /* - * Utility to reset a timer to go off some time in the future. + * set_timer_callback: + * + * Utility to reset a timer to go off some time in the future. */ static void set_timer_callback(struct timer_list *timer, int ticks) @@ -67,10 +84,14 @@ } -/* - * Take care of letting any waiting processes know that - * now would be a good time to do a read(). Called - * whenever a state transition occurs, real or synthetic. +/** + * wake_readers: + * + * Take care of letting any waiting processes know that + * now would be a good time to do a read(). Called + * whenever a state transition occurs, real or synthetic. Also + * issue any SIGIO's to programs that use SIGIO on mice (eg + * Executor) */ static void wake_readers(void) @@ -112,7 +133,10 @@ static struct timer_list tap_timer = { NULL, NULL, 0, 0, tap_timeout }; -/* +/** + * tap_timeout: + * @data: Unused + * * This callback goes off a short time after an up/down transition; * before it goes off, transitions will be considered part of a * single PS/2 event and counted in transition_count. Once the @@ -136,7 +160,9 @@ } -/* +/** + * notify_pad_up_down: + * * Called by the raw pad read routines when a (debounced) up/down * transition is detected. */ @@ -159,6 +185,13 @@ wake_readers(); } +/** + * read_button: + * @b: pointer to the button status. + * + * The actual button state depends on what we are seeing. We have to check + * for the tap gesture and also for dragging. + */ static void read_button(int *b) { @@ -216,12 +249,17 @@ static struct timer_list bounce_timer = { NULL, NULL, 0, 0, bounce_timeout }; + +/** + * bounce_timeout: + * @data: Unused + * + * No further up/down transitions happened within the + * bounce period, so treat this as a genuine transition. + */ + static void bounce_timeout(unsigned long data) { - /* - * No further up/down transitions happened within the - * bounce period, so treat this as a genuine transition. - */ switch(bounce) { case NO_BOUNCE: @@ -230,7 +268,7 @@ * Strange; the timer callback should only go off if * we were expecting to do bounce processing! */ - printk("pc110pad, bounce_timeout: bounce flag not set!\n"); + printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n"); break; } case JUST_GONE_UP: @@ -242,7 +280,7 @@ bounce=NO_BOUNCE; if(debounced_down==raw_down) { - printk("pc110pad, bounce_timeout: raw already debounced!\n"); + printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n"); } debounced_down=raw_down; @@ -263,10 +301,17 @@ } -/* +/** + * pad_irq: + * @irq: Interrupt number + * @ptr: Unused + * @regs: Unused + * * Callback when pad's irq goes off; copies values in to raw_* globals; - * initiates debounce processing. + * initiates debounce processing. This isn't SMP safe however there are + * no SMP machines with a PC110 touchpad on them. */ + static void pad_irq(int irq, void *ptr, struct pt_regs *regs) { @@ -356,6 +401,18 @@ } } +/** + * read_raw_pad: + * @down: set if the pen is down + * @debounced: set if the debounced pen position is down + * @x: X position + * @y: Y position + * + * Retrieve the data saved by the interrupt handler and indicate we + * have no more pending XY to do. + * + * FIXME: We should switch to a spinlock for this. + */ static void read_raw_pad(int *down, int *debounced, int *x, int *y) { @@ -384,6 +441,12 @@ static int read_bytes[3]; static int read_byte_count=0; +/** + * sample_raw: + * @d: sample buffer + * + * Retrieve a triple of sample data. + */ static void sample_raw(int d[3]) @@ -393,6 +456,14 @@ d[2]=raw_data[2]; } +/** + * sample_rare: + * @d: sample buffer + * + * Retrieve a triple of sample data and sanitize it. We do the needed + * scaling and masking to get the current status. + */ + static void sample_rare(int d[3]) { @@ -409,20 +480,40 @@ d[2]=thisy%256; } +/** + * sample_debug: + * @d: sample buffer + * + * Retrieve a triple of sample data and mix it up with the state + * information in the gesture parser. Not useful for normal users but + * handy when debugging + */ static void sample_debug(int d[3]) { int thisd, thisdd, thisx, thisy; int b; + unsigned long flags; + + save_flags(flags); cli(); read_raw_pad(&thisd, &thisdd, &thisx, &thisy); d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce; d[1]=(recent_transition?0x80:0)+transition_count; read_button(&b); d[2]=(synthesize_tap<<4) | (b?0x01:0); - sti(); + restore_flags(flags); } +/** + * sample_ps2: + * @d: sample buffer + * + * Retrieve a triple of sample data and turn the debounced tap and + * stroke information into what appears to be a PS/2 mouse. This means + * the PC110 pad needs no funny application side support. + */ + static void sample_ps2(int d[3]) { @@ -474,7 +565,16 @@ } - +/** + * fasync_pad: + * @fd: file number for the file + * @filp: file handle + * @on: 1 to add, 0 to remove a notifier + * + * Update the queue of asynchronous event notifiers. We can use the + * same helper the mice do and that does almost everything we need. + */ + static int fasync_pad(int fd, struct file *filp, int on) { int retval; @@ -486,9 +586,16 @@ } -/* - * close access to the pad +/** + * close_pad: + * @inode: inode of pad + * @file: file handle to pad + * + * Close access to the pad. We turn the pad power off if this is the + * last user of the pad. I've not actually measured the power draw but + * the DOS driver is careful to do this so we follow suit. */ + static int close_pad(struct inode * inode, struct file * file) { fasync_pad(-1, file, 0); @@ -500,9 +607,17 @@ } -/* - * open access to the pad +/** + * open_pad: + * @inode: inode of pad + * @file: file handle to pad + * + * Open access to the pad. We turn the pad off first (we turned it off + * on close but if this is the first open after a crash the state is + * indeterminate). The device has a small fifo so we empty that before + * we kick it back into action. */ + static int open_pad(struct inode * inode, struct file * file) { unsigned long flags; @@ -533,15 +648,31 @@ } -/* - * writes are disallowed +/** + * write_pad: + * @file: File handle to the pad + * @buffer: Unused + * @count: Unused + * @ppos: Unused + * + * Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone + * seems happy with this and not faking the write modes. */ + static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos) { return -EINVAL; } +/* + * new_sample: + * @d: sample buffer + * + * Fetch a new sample according the current mouse mode the pad is + * using. + */ + void new_sample(int d[3]) { switch(current_params.mode) @@ -554,9 +685,17 @@ } -/* - * Read pad data. Currently never blocks. +/** + * read_pad: + * @file: File handle to pad + * @buffer: Target for the mouse data + * @count: Buffer length + * @ppos: Offset (unused) + * + * Read data from the pad. We use the reader_lock to avoid mess when there are + * two readers. This shouldnt be happening anyway but we play safe. */ + static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos) { int r; @@ -578,8 +717,14 @@ } -/* - * select for pad input +/** + * pad_poll: + * @file: File of the pad device + * @wait: Poll table + * + * The pad is ready to read if there is a button or any position change + * pending in the queue. The reading and interrupt routines maintain the + * required state for us and do needed wakeups. */ static unsigned int pad_poll(struct file *file, poll_table * wait) @@ -591,6 +736,20 @@ } +/** + * pad_ioctl; + * @inode: Inode of the pad + * @file: File handle to the pad + * @cmd: Ioctl command + * @arg: Argument pointer + * + * The PC110 pad supports two ioctls both of which use the pc110pad_params + * structure. GETP queries the current pad status. SETP changes the pad + * configuration. Changing configuration during normal mouse operations + * may give momentarily odd results as things like tap gesture state + * may be lost. + */ + static int pad_ioctl(struct inode *inode, struct file * file, unsigned int cmd, unsigned long arg) { @@ -627,19 +786,13 @@ static struct file_operations pad_fops = { - NULL, /* pad_seek */ - read_pad, - write_pad, - NULL, /* pad_readdir */ - pad_poll, - pad_ioctl, - NULL, /* pad_mmap */ - open_pad, - NULL, /* flush */ - close_pad, - NULL, /* fsync */ - fasync_pad, - NULL /* lock */ + read: read_pad, + write: write_pad, + poll: pad_poll, + ioctl: pad_ioctl, + open: open_pad, + release: close_pad, + fasync: fasync_pad, }; @@ -648,6 +801,15 @@ }; +/** + * pc110pad_init: + * + * We configure the pad with the default parameters (that is PS/2 + * emulation mode. We then claim the needed I/O and interrupt resources. + * Finally as a matter of paranoia we turn the pad off until we are + * asked to open it by an application. + */ + int pc110pad_init(void) { current_params = default_params; @@ -675,6 +837,13 @@ #ifdef MODULE +/** + * pc110pad_unload: + * + * Free the resources we acquired when the module was loaded. We also + * turn the pad off to be sure we don't leave it using power. + */ + static void pc110pad_unload(void) { outb(0x30, current_params.io+2); /* switch off digitiser */ diff -u --recursive --new-file v2.3.42/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.3.42/linux/drivers/char/pc_keyb.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/pc_keyb.c Wed Feb 9 20:08:09 2000 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -412,16 +413,13 @@ #endif } -static unsigned char kbd_exists = 1; - static inline void handle_keyboard_event(unsigned char scancode) { - kbd_exists = 1; #ifdef CONFIG_VT if (do_acknowledge(scancode)) handle_scancode(scancode, !(scancode & 0x80)); #endif - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); } /* @@ -485,8 +483,6 @@ { int retries = 3; - if (!kbd_exists) return 0; - do { unsigned long timeout = KBD_TIMEOUT; @@ -504,7 +500,6 @@ #ifdef KBD_REPORT_TIMEOUTS printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?\n"); #endif - kbd_exists = 0; return 0; } } @@ -512,7 +507,6 @@ #ifdef KBD_REPORT_TIMEOUTS printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n"); #endif - kbd_exists = 0; return 0; } @@ -971,18 +965,12 @@ } struct file_operations psaux_fops = { - NULL, /* seek */ - read_aux, - write_aux, - NULL, /* readdir */ - aux_poll, - NULL, /* ioctl */ - NULL, /* mmap */ - open_aux, - NULL, /* flush */ - release_aux, - NULL, - fasync_aux, + read: read_aux, + write: write_aux, + poll: aux_poll, + open: open_aux, + release: release_aux, + fasync: fasync_aux, }; /* diff -u --recursive --new-file v2.3.42/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.3.42/linux/drivers/char/pcwd.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/char/pcwd.c Wed Feb 9 11:42:35 2000 @@ -574,19 +574,11 @@ } static struct file_operations pcwd_fops = { - NULL, /* Seek */ - pcwd_read, /* Read */ - pcwd_write, /* Write */ - NULL, /* Readdir */ - NULL, /* Poll */ - pcwd_ioctl, /* IOctl */ - NULL, /* MMAP */ - pcwd_open, /* Open */ - NULL, /* flush */ - pcwd_close, /* Release */ - NULL, /* Fsync */ - NULL, /* Fasync */ - NULL, /* Lock */ + read: pcwd_read, + write: pcwd_write, + ioctl: pcwd_ioctl, + open: pcwd_open, + release: pcwd_close, }; static struct miscdevice pcwd_miscdev = { diff -u --recursive --new-file v2.3.42/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.3.42/linux/drivers/char/ppdev.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/char/ppdev.c Wed Feb 9 11:42:35 2000 @@ -4,7 +4,7 @@ * This is the code behind /dev/parport* -- it allows a user-space * application to use the parport subsystem. * - * Copyright (C) 1998-9 Tim Waugh + * Copyright (C) 1998-2000 Tim Waugh * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -506,9 +506,13 @@ if (minor >= PARPORT_MAX) return -ENXIO; + MOD_INC_USE_COUNT; + pp = kmalloc (sizeof (struct pp_struct), GFP_KERNEL); - if (!pp) + if (!pp) { + MOD_DEC_USE_COUNT; return -ENOMEM; + } pp->state.mode = IEEE1284_MODE_COMPAT; pp->state.phase = init_phase (pp->state.mode); @@ -524,7 +528,6 @@ pp->pdev = NULL; file->private_data = pp; - MOD_INC_USE_COUNT; return 0; } @@ -567,16 +570,13 @@ } static struct file_operations pp_fops = { - pp_lseek, - pp_read, - pp_write, - NULL, /* pp_readdir */ - pp_poll, - pp_ioctl, - NULL, /* pp_mmap */ - pp_open, - NULL, /* pp_flush */ - pp_release + llseek: pp_lseek, + read: pp_read, + write: pp_write, + poll: pp_poll, + ioctl: pp_ioctl, + open: pp_open, + release: pp_release, }; static int __init ppdev_init (void) diff -u --recursive --new-file v2.3.42/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.3.42/linux/drivers/char/qpmouse.c Mon Oct 11 15:38:14 1999 +++ linux/drivers/char/qpmouse.c Wed Feb 9 11:42:35 2000 @@ -290,18 +290,12 @@ } struct file_operations qp_fops = { - NULL, /* seek */ - read_qp, - write_qp, - NULL, /* readdir */ - poll_qp, - NULL, /* ioctl */ - NULL, /* mmap */ - open_qp, - NULL, /* flush */ - release_qp, - NULL, - fasync_qp, + read: read_qp, + write: write_qp, + poll: poll_qp, + open: open_qp, + release: release_qp, + fasync: fasync_qp, }; /* diff -u --recursive --new-file v2.3.42/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.3.42/linux/drivers/char/random.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/random.c Wed Feb 9 11:42:35 2000 @@ -1637,29 +1637,16 @@ } struct file_operations random_fops = { - NULL, /* random_lseek */ - random_read, - random_write, - NULL, /* random_readdir */ - random_poll, /* random_poll */ - random_ioctl, - NULL, /* random_mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL /* no special release code */ + read: random_read, + write: random_write, + poll: random_poll, + ioctl: random_ioctl, }; struct file_operations urandom_fops = { - NULL, /* unrandom_lseek */ - urandom_read, - random_write, - NULL, /* urandom_readdir */ - NULL, /* urandom_poll */ - random_ioctl, - NULL, /* urandom_mmap */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL /* no special release code */ + read: urandom_read, + write: random_write, + ioctl: random_ioctl, }; /*************************************************************** diff -u --recursive --new-file v2.3.42/linux/drivers/char/raw.c linux/drivers/char/raw.c --- v2.3.42/linux/drivers/char/raw.c Thu Jan 6 12:57:47 2000 +++ linux/drivers/char/raw.c Wed Feb 9 11:42:35 2000 @@ -33,31 +33,15 @@ static struct file_operations raw_fops = { - NULL, /* llseek */ - raw_read, /* read */ - raw_write, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - raw_open, /* open */ - NULL, /* flush */ - raw_release, /* release */ - NULL /* fsync */ + read: raw_read, + write: raw_write, + open: raw_open, + release: raw_release, }; static struct file_operations raw_ctl_fops = { - NULL, /* llseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - raw_ctl_ioctl, /* ioctl */ - NULL, /* mmap */ - raw_open, /* open */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* fsync */ + ioctl: raw_ctl_ioctl, + open: raw_open, }; void __init raw_init(void) diff -u --recursive --new-file v2.3.42/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.3.42/linux/drivers/char/rtc.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/rtc.c Mon Feb 7 09:51:43 2000 @@ -34,10 +34,11 @@ * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. * 1.09a Pete Zaitcev: Sun SPARC * 1.09b Jeff Garzik: Modularize, init cleanup - * + * 1.09c Jeff Garzik: SMP cleanup + * 1.10 Paul Barton-Davis: add support for async I/O */ -#define RTC_VERSION "1.09b" +#define RTC_VERSION "1.10" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -80,6 +81,8 @@ * ioctls. */ +static struct fasync_struct *rtc_async_queue; + static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; @@ -153,6 +156,9 @@ wake_up_interruptible(&rtc_wait); + if (rtc_async_queue) + kill_fasync (rtc_async_queue, SIGIO, POLL_IN); + if (atomic_read(&rtc_status) & RTC_TIMER_ON) mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); } @@ -480,6 +486,12 @@ return 0; } +static int rtc_fasync (int fd, struct file *filp, int on) + +{ + return fasync_helper (fd, filp, on, &rtc_async_queue); +} + static int rtc_release(struct inode *inode, struct file *file) { /* @@ -504,6 +516,10 @@ del_timer(&rtc_irq_timer); } + if (file->f_flags & FASYNC) { + rtc_fasync (-1, file, 0); + } + MOD_DEC_USE_COUNT; spin_lock_irqsave (&rtc_lock, flags); @@ -533,16 +549,13 @@ */ static struct file_operations rtc_fops = { - rtc_llseek, - rtc_read, - NULL, /* No write */ - NULL, /* No readdir */ - rtc_poll, - rtc_ioctl, - NULL, /* No mmap */ - rtc_open, - NULL, /* flush */ - rtc_release + llseek: rtc_llseek, + read: rtc_read, + poll: rtc_poll, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, + fasync: rtc_fasync, }; static struct miscdevice rtc_dev= diff -u --recursive --new-file v2.3.42/linux/drivers/char/saa5249.c linux/drivers/char/saa5249.c --- v2.3.42/linux/drivers/char/saa5249.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/saa5249.c Wed Feb 9 18:48:03 2000 @@ -256,7 +256,7 @@ static struct i2c_driver i2c_driver_videotext = { IF_NAME, /* name */ - I2C_DRIVERID_VIDEOTEXT, /* in i2c.h */ + I2C_DRIVERID_SAA5249, /* in i2c.h */ I2C_DF_NOTIFY, saa5249_probe, saa5249_detach, diff -u --recursive --new-file v2.3.42/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v2.3.42/linux/drivers/char/softdog.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/char/softdog.c Wed Feb 9 11:42:35 2000 @@ -158,18 +158,10 @@ static struct file_operations softdog_fops= { - NULL, /* Seek */ - NULL, /* Read */ - softdog_write, /* Write */ - NULL, /* Readdir */ - NULL, /* Select */ - softdog_ioctl, /* Ioctl */ - NULL, /* MMap */ - softdog_open, - NULL, /* flush */ - softdog_release, - NULL, - NULL /* Fasync */ + write: softdog_write, + ioctl: softdog_ioctl, + open: softdog_open, + release: softdog_release, }; static struct miscdevice softdog_miscdev= diff -u --recursive --new-file v2.3.42/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.3.42/linux/drivers/char/stallion.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/char/stallion.c Wed Feb 9 11:42:35 2000 @@ -743,19 +743,9 @@ * to get at port stats - only not using the port device itself. */ static struct file_operations stl_fsiomem = { - NULL, /* llseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - stl_memioctl, /* ioctl */ - NULL, /* mmap */ - stl_memopen, /* open */ - NULL, /* flush */ - stl_memclose, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - NULL /* lock */ + ioctl: stl_memioctl, + open: stl_memopen, + release: stl_memclose, }; /*****************************************************************************/ diff -u --recursive --new-file v2.3.42/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.3.42/linux/drivers/char/sx.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/sx.c Wed Feb 9 11:42:35 2000 @@ -531,20 +531,9 @@ */ static struct file_operations sx_fw_fops = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* select */ - sx_fw_ioctl, - NULL, /* mmap */ - sx_fw_open, -#ifndef TWO_ZERO - NULL, /* flush */ -#endif - sx_fw_release, - NULL, /* fsync */ - NULL, /* fasync */ + ioctl: sx_fw_ioctl, + open: sx_fw_open, + release: sx_fw_release, }; struct miscdevice sx_fw_device = { diff -u --recursive --new-file v2.3.42/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.3.42/linux/drivers/char/tpqic02.c Fri Jan 7 19:13:21 2000 +++ linux/drivers/char/tpqic02.c Wed Feb 9 11:42:35 2000 @@ -2765,18 +2765,12 @@ /* These are (most) of the interface functions: */ static struct file_operations qic02_tape_fops = { - qic02_tape_lseek, /* not allowed */ - qic02_tape_read, /* read */ - qic02_tape_write, /* write */ - NULL, /* readdir not allowed */ - NULL, /* poll ??? */ - qic02_tape_ioctl, /* ioctl */ - NULL, /* mmap not allowed */ - qic02_tape_open, /* open */ - NULL, /* flush */ - qic02_tape_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ + llseek: qic02_tape_lseek, /* not allowed */ + read: qic02_tape_read, + write: qic02_tape_write, + ioctl: qic02_tape_ioctl, + open: qic02_tape_open, + release: qic02_tape_release, }; diff -u --recursive --new-file v2.3.42/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.3.42/linux/drivers/char/tty_io.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/char/tty_io.c Wed Feb 9 11:42:35 2000 @@ -358,33 +358,23 @@ } static struct file_operations tty_fops = { - tty_lseek, - tty_read, - tty_write, - NULL, /* tty_readdir */ - tty_poll, - tty_ioctl, - NULL, /* tty_mmap */ - tty_open, - NULL, /* flush */ - tty_release, - NULL, /* tty_fsync */ - tty_fasync + llseek: tty_lseek, + read: tty_read, + write: tty_write, + poll: tty_poll, + ioctl: tty_ioctl, + open: tty_open, + release: tty_release, + fasync: tty_fasync, }; static struct file_operations hung_up_tty_fops = { - tty_lseek, - hung_up_tty_read, - hung_up_tty_write, - NULL, /* hung_up_tty_readdir */ - hung_up_tty_poll, - hung_up_tty_ioctl, - NULL, /* hung_up_tty_mmap */ - NULL, /* hung_up_tty_open */ - NULL, /* flush */ - tty_release, /* hung_up_tty_release */ - NULL, /* hung_up_tty_fsync */ - NULL /* hung_up_tty_fasync */ + llseek: tty_lseek, + read: hung_up_tty_read, + write: hung_up_tty_write, + poll: hung_up_tty_poll, + ioctl: hung_up_tty_ioctl, + release: tty_release, }; /* diff -u --recursive --new-file v2.3.42/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- v2.3.42/linux/drivers/char/vc_screen.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/char/vc_screen.c Wed Feb 9 11:42:35 2000 @@ -297,17 +297,10 @@ } static struct file_operations vcs_fops = { - vcs_lseek, /* lseek */ - vcs_read, /* read */ - vcs_write, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - vcs_open, /* open */ - NULL, /* flush */ - NULL, /* release */ - NULL /* fsync */ + llseek: vcs_lseek, + read: vcs_read, + write: vcs_write, + open: vcs_open, }; int __init vcs_init(void) diff -u --recursive --new-file v2.3.42/linux/drivers/char/videodev.c linux/drivers/char/videodev.c --- v2.3.42/linux/drivers/char/videodev.c Tue Jan 4 13:57:16 2000 +++ linux/drivers/char/videodev.c Wed Feb 9 11:42:35 2000 @@ -302,22 +302,16 @@ static struct file_operations video_fops= { - video_lseek, - video_read, - video_write, - NULL, /* readdir */ -#if LINUX_VERSION_CODE >= 0x020100 - video_poll, /* poll */ -#else - NULL, + llseek: video_lseek, + read: video_read, + write: video_write, + ioctl: video_ioctl, + mmap: video_mmap, + open: video_open, + release: video_release, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + poll: video_poll, #endif - video_ioctl, - video_mmap, - video_open, -#if LINUX_VERSION_CODE >= 0x020100 - NULL, /* flush */ -#endif - video_release }; /* diff -u --recursive --new-file v2.3.42/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.3.42/linux/drivers/char/vt.c Fri Oct 22 13:21:48 1999 +++ linux/drivers/char/vt.c Wed Feb 9 20:08:09 2000 @@ -804,10 +804,12 @@ * When we actually do the console switch, * make sure we are atomic with respect to * other console switches.. + * + * Damn! Was it difficult to make this clean? */ - start_bh_atomic(); + disable_bh(CONSOLE_BH); complete_change_console(newvt); - end_bh_atomic(); + enable_bh(CONSOLE_BH); } } diff -u --recursive --new-file v2.3.42/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.3.42/linux/drivers/char/wdt.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/wdt.c Thu Feb 10 12:31:07 2000 @@ -62,8 +62,13 @@ #ifndef MODULE -/* - * Setup options +/** + * wdt_setup: + * @str: command line string + * + * Setup options. The board isn't really probe-able so we have to + * get the user to tell us the configuration. Sane people build it + * modular but the others come here. */ static int __init wdt_setup(char *str) @@ -108,6 +113,17 @@ * Kernel methods. */ + +/** + * wdt_status: + * + * Extract the status information from a WDT watchdog device. There are + * several board variants so we have to know which bits are valid. Some + * bits default to one and some to zero in order to be maximally painful. + * + * we then map the bits onto the status ioctl flags. + */ + static int wdt_status(void) { /* @@ -134,11 +150,26 @@ return flag; } +/** + * wdt_interrupt: + * @irq: Interrupt number + * @dev_id: Unused as we don't allow multiple devices. + * @regs: Unused. + * + * Handle an interrupt from the board. These are raised when the status + * map changes in what the board considers an interesting way. That means + * a failure condition occuring. + * + * FIXME: We need to pass a dev_id as the PCI card can share irqs + * although its arguably a _very_ dumb idea to share watchdog + * irq lines + */ + void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* * Read the status register see what is up and - * then printk it. + * then printk it. */ unsigned char status=inb_p(WDT_SR); @@ -175,6 +206,13 @@ return -ESPIPE; } +/** + * wdt_ping: + * + * Reload counter one with the watchdog timeout. We don't bother reloading + * the cascade counter. + */ + static void wdt_ping(void) { /* Write a watchdog value */ @@ -184,6 +222,17 @@ outb_p(0, WDT_DC); } +/** + * wdt_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { /* Can't seek (pwrite) on this device */ @@ -198,8 +247,15 @@ return 0; } -/* - * Read reports the temperature in degrees Fahrenheit. +/** + * wdt_read: + * @file: file handle to the watchdog board + * @buf: buffer to write 1 byte into + * @count: length of buffer + * @ptr: offset (no seek allowed) + * + * Read reports the temperature in degrees Fahrenheit. The API is in + * farenheit. It was designed by an imperial measurement luddite. */ static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *ptr) @@ -225,6 +281,18 @@ } } +/** + * wdt_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. We only actually usefully support + * querying capabilities and current status. + */ + static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -254,6 +322,18 @@ } } +/** + * wdt_open: + * @inode: inode of device + * @file: file handle to device + * + * One of our two misc devices has been opened. The watchdog device is + * single open and on opening we load the counters. Counter zero is a + * 100Hz cascade, into counter 1 which downcounts to reboot. When the + * counter triggers counter 2 downcounts the length of the reset pulse + * which set set to be as long as possible. + */ + static int wdt_open(struct inode *inode, struct file *file) { switch(MINOR(inode->i_rdev)) @@ -284,6 +364,18 @@ } } +/** + * wdt_close: + * @inode: inode to board + * @file: file handle to board + * + * The watchdog has a configurable API. There is a religious dispute + * between people who want their watchdog to be able to shut down and + * those who want to be sure if the watchdog manager dies the machine + * reboots. In the former case we disable the counters, in the latter + * case you have to open it again very soon. + */ + static int wdt_release(struct inode *inode, struct file *file) { if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) @@ -298,8 +390,16 @@ return 0; } -/* - * Notifier for system down +/** + * notify_sys: + * @this: our notifier block + * @code: the event being reported + * @unused: unused + * + * Our notifier is called on system shutdowns. We want to turn the card + * off at reboot otherwise the machine will reboot again during memory + * test or worse yet during the following fsck. This would suck, in fact + * trust me - if it happens it does suck. */ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, @@ -320,16 +420,12 @@ static struct file_operations wdt_fops = { - wdt_llseek, - wdt_read, - wdt_write, - NULL, /* No Readdir */ - NULL, /* No Select */ - wdt_ioctl, - NULL, /* No mmap */ - wdt_open, - NULL, /* flush */ - wdt_release + llseek: wdt_llseek, + read: wdt_read, + write: wdt_write, + ioctl: wdt_ioctl, + open: wdt_open, + release: wdt_release, }; static struct miscdevice wdt_miscdev= @@ -364,6 +460,16 @@ #define wdt_init init_module +/** + * cleanup_module: + * + * Unload the watchdog. You cannot do this with any file handles open. + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. We won't get the interrupt but the board + * will not touch PC memory so all is fine. You just have to load a new + * module in 60 seconds or reboot. + */ + void cleanup_module(void) { misc_deregister(&wdt_miscdev); @@ -377,6 +483,14 @@ #endif +/** + * wdt_init: + * + * Set up the WDT watchdog board. All we have to do is grab the + * resources we require and bitch if anyone beat us to them. + * The open() function will actually kick the board off. + */ + int __init wdt_init(void) { printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq); diff -u --recursive --new-file v2.3.42/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c --- v2.3.42/linux/drivers/i2c/i2c-algo-bit.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/i2c/i2c-algo-bit.c Wed Feb 9 18:48:03 2000 @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ /* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters */ /* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-99 Simon G. Vogl +/* Copyright (C) 1995-2000 Simon G. Vogl 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 @@ -21,35 +21,15 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-algo-bit.c,v 1.21 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-algo-bit.c,v 1.26 2000/01/24 02:06:33 mds Exp $ */ #include #include #include #include #include -#if LINUX_VERSION_CODE >= 0x020135 #include -#else -#define __init -#endif - -#if LINUX_VERSION_CODE >= 0x020100 -# include -#else -# include -#endif - -/* 2.0.0 kernel compatibility */ -#if LINUX_VERSION_CODE < 0x020100 -#define MODULE_AUTHOR(noone) -#define MODULE_DESCRIPTION(none) -#define MODULE_PARM(no,param) -#define MODULE_PARM_DESC(no,description) -#define EXPORT_SYMBOL(noexport) -#define EXPORT_NO_SYMBOLS -#endif - +#include #include #include #include @@ -69,13 +49,8 @@ /* respectively. This makes sure that the algorithm works. Some chips */ /* might not like this, as they have an internal timeout of some mils */ /* -#if LINUX_VERSION_CODE >= 0x02016e #define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ if (need_resched) schedule(); -#else -#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ - if (need_resched) schedule(); -#endif */ @@ -100,22 +75,22 @@ static inline void sdalo(struct i2c_algo_bit_data *adap) { - setsda(adap,0); - udelay(adap->udelay); + setsda(adap,0); + udelay(adap->udelay); } static inline void sdahi(struct i2c_algo_bit_data *adap) { - setsda(adap,1); - udelay(adap->udelay); + setsda(adap,1); + udelay(adap->udelay); } static inline void scllo(struct i2c_algo_bit_data *adap) { - setscl(adap,0); - udelay(adap->udelay); + setscl(adap,0); + udelay(adap->udelay); #ifdef SLO_IO - SLO_IO + SLO_IO #endif } @@ -145,13 +120,8 @@ if (start+adap->timeout <= jiffies) { return -ETIMEDOUT; } -#if LINUX_VERSION_CODE >= 0x02016e if (current->need_resched) schedule(); -#else - if (need_resched) - schedule(); -#endif } DEBSTAT(printk("needed %ld jiffies\n", jiffies-start)); #ifdef SLO_IO @@ -259,7 +229,7 @@ }; indata *= 2; if ( getsda(adap) ) - indata |= 0x01; + indata |= 0x01; scllo(adap); } /* assert: scl is low */ @@ -280,13 +250,14 @@ } scl=getscl(adap); printk("i2c-algo-bit.o: Adapter: %s scl: %d sda: %d -- testing...\n", - name,getscl(adap),getsda(adap)); + name,getscl(adap),getsda(adap)); if (!scl || !sda ) { printk("i2c-algo-bit.o: %s seems to be busy.\n",name); goto bailout; } sdalo(adap); - printk("i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + printk("i2c-algo-bit.o:1 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); if ( 0 != getsda(adap) ) { printk("i2c-algo-bit.o: %s SDA stuck high!\n",name); sdahi(adap); @@ -298,18 +269,21 @@ goto bailout; } sdahi(adap); - printk("i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + printk("i2c-algo-bit.o:2 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); if ( 0 == getsda(adap) ) { printk("i2c-algo-bit.o: %s SDA stuck low!\n",name); sdahi(adap); goto bailout; } if ( 0 == getscl(adap) ) { - printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n",name); + printk("i2c-algo-bit.o: %s SCL unexpected low while SDA high!\n", + name); goto bailout; } scllo(adap); - printk("i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + printk("i2c-algo-bit.o:3 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); if ( 0 != getscl(adap) ) { printk("i2c-algo-bit.o: %s SCL stuck high!\n",name); sclhi(adap); @@ -321,7 +295,8 @@ goto bailout; } sclhi(adap); - printk("i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + printk("i2c-algo-bit.o:4 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); if ( 0 == getscl(adap) ) { printk("i2c-algo-bit.o: %s SCL stuck low!\n",name); sclhi(adap); @@ -366,7 +341,8 @@ i2c_start(adap); udelay(adap->udelay); } - DEB2(if (i) printk("i2c-algo-bit.o: needed %d retries for %d\n",i,addr)); + DEB2(if (i) printk("i2c-algo-bit.o: needed %d retries for %d\n", + i,addr)); return ret; } @@ -391,7 +367,8 @@ printk("i2c-algo-bit.o: %s i2c_write: error - bailout.\n", i2c_adap->name); i2c_stop(adap); - return (retval<0)? retval : -EFAULT; /* got a better one ?? */ + return (retval<0)? retval : -EFAULT; + /* got a better one ?? */ } #if 0 /* from asm/delay.h */ @@ -447,8 +424,8 @@ * -x an error occured (like: -EREMOTEIO if the device did not answer, or * -ETIMEDOUT, for example if the lines are stuck...) */ -static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, - int retries) +static inline int bit_doAddress(struct i2c_adapter *i2c_adap, + struct i2c_msg *msg, int retries) { unsigned short flags = msg->flags; struct i2c_algo_bit_data *adap = i2c_adap->algo_data; @@ -486,6 +463,8 @@ addr = ( msg->addr << 1 ); if (flags & I2C_M_RD ) addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR ) + addr ^= 1; ret = try_address(i2c_adap, addr, retries); if (ret!=1) { return -EREMOTEIO; @@ -505,11 +484,16 @@ i2c_start(adap); for (i=0;iretries); - if (ret != 0) { - DEB2(printk("i2c-algo-bit.o: NAK from device adr %#2x msg #%d\n" - ,msgs[i].addr,i)); - return (ret<0) ? ret : -EREMOTEIO; + if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i) { + i2c_repstart(adap); + } + ret = bit_doAddress(i2c_adap,pmsg,i2c_adap->retries); + if (ret != 0) { + DEB2(printk("i2c-algo-bit.o: NAK from device adr %#2x msg #%d\n" + ,msgs[i].addr,i)); + return (ret<0) ? ret : -EREMOTEIO; + } } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ @@ -526,9 +510,6 @@ return (ret<0) ? ret : -EREMOTEIO; } } - if (ialgo_data; + struct i2c_algo_bit_data *bit_adap = adap->algo_data; if (bit_test) { int ret = test_bus(bit_adap, adap->name); @@ -573,7 +555,8 @@ return -ENODEV; } - DEB2(printk("i2c-algo-bit.o: hw routines for %s registered.\n",adap->name)); + DEB2(printk("i2c-algo-bit.o: hw routines for %s registered.\n", + adap->name)); /* register new adapter to i2c module... */ @@ -585,8 +568,9 @@ /* scan bus */ if (bit_scan) { - int ack; - printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n", adap->name); + int ack; + printk(KERN_INFO " i2c-algo-bit.o: scanning bus %s.\n", + adap->name); for (i = 0x00; i < 0xff; i+=2) { i2c_start(bit_adap); ack = i2c_outb(adap,i); @@ -642,7 +626,8 @@ MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); -MODULE_PARM_DESC(i2c_debug,"debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); int init_module(void) { diff -u --recursive --new-file v2.3.42/linux/drivers/i2c/i2c-algo-pcf.c linux/drivers/i2c/i2c-algo-pcf.c --- v2.3.42/linux/drivers/i2c/i2c-algo-pcf.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/i2c/i2c-algo-pcf.c Wed Feb 9 18:48:03 2000 @@ -2,8 +2,8 @@ /* ------------------------------------------------------------------------- */ /* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters */ /* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-97 Simon G. Vogl - 1998-99 Hans Berglund +/* Copyright (C) 1995-1997 Simon G. Vogl + 1998-2000 Hans Berglund 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 @@ -20,43 +20,22 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* With some changes from Kyösti Mälkki and even +/* With some changes from Kyösti Mälkki and Frodo Looijaard */ -/* $Id: i2c-algo-pcf.c,v 1.15 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-algo-pcf.c,v 1.20 2000/01/24 02:06:33 mds Exp $ */ #include #include #include #include #include -#if LINUX_VERSION_CODE >= 0x020135 #include -#else -#define __init -#endif - -#if LINUX_VERSION_CODE >= 0x020100 -# include -#else -# include -#endif - - +#include #include #include #include -/* 2.0.0 kernel compatibility */ -#if LINUX_VERSION_CODE < 0x020100 -#define MODULE_AUTHOR(noone) -#define MODULE_DESCRIPTION(none) -#define MODULE_PARM(no,param) -#define MODULE_PARM_DESC(no,description) -#define EXPORT_SYMBOL(noexport) -#define EXPORT_NO_SYMBOLS -#endif - #include #include #include "i2c-pcf8584.h" @@ -74,13 +53,8 @@ /* respectively. This makes sure that the algorithm works. Some chips */ /* might not like this, as they have an internal timeout of some mils */ /* -#if LINUX_VERSION_CODE >= 0x02016e #define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ if (need_resched) schedule(); -#else -#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ - if (need_resched) schedule(); -#endif */ @@ -108,52 +82,42 @@ /* --- other auxiliary functions -------------------------------------- */ -#if LINUX_VERSION_CODE < 0x02017f -static void schedule_timeout(int j) -{ - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + j; - schedule(); -} -#endif - - static void i2c_start(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk("S ")); - set_pcf(adap, 1, I2C_PCF_START); + DEBPROTO(printk("S ")); + set_pcf(adap, 1, I2C_PCF_START); } static void i2c_repstart(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk(" Sr ")); - set_pcf(adap, 1, I2C_PCF_REPSTART); + DEBPROTO(printk(" Sr ")); + set_pcf(adap, 1, I2C_PCF_REPSTART); } static void i2c_stop(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk("P\n")); - set_pcf(adap, 1, I2C_PCF_STOP); + DEBPROTO(printk("P\n")); + set_pcf(adap, 1, I2C_PCF_STOP); } static int wait_for_bb(struct i2c_algo_pcf_data *adap) { - int timeout = DEF_TIMEOUT; - int status; + int timeout = DEF_TIMEOUT; + int status; - status = get_pcf(adap, 1); - while (timeout-- && !(status & I2C_PCF_BB)) { - udelay(1000); /* How much is this? */ - status = get_pcf(adap, 1); - } - if (timeout<=0) - printk("Timeout waiting for Bus Busy\n"); - /* - set_pcf(adap, 1, I2C_PCF_STOP); - */ - return(timeout<=0); + status = get_pcf(adap, 1); + while (timeout-- && !(status & I2C_PCF_BB)) { + udelay(1000); /* How much is this? */ + status = get_pcf(adap, 1); + } + if (timeout<=0) + printk("Timeout waiting for Bus Busy\n"); + /* + set_pcf(adap, 1, I2C_PCF_STOP); + */ + return(timeout<=0); } @@ -165,17 +129,17 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) { - int timeout = DEF_TIMEOUT; + int timeout = DEF_TIMEOUT; - *status = get_pcf(adap, 1); - while (timeout-- && (*status & I2C_PCF_PIN)) { - adap->waitforpin(); - *status = get_pcf(adap, 1); - } - if (timeout <= 0) - return(-1); - else - return(0); + *status = get_pcf(adap, 1); + while (timeout-- && (*status & I2C_PCF_PIN)) { + adap->waitforpin(); + *status = get_pcf(adap, 1); + } + if (timeout <= 0) + return(-1); + else + return(0); } @@ -231,7 +195,8 @@ goto bailout; } sdalo(adap); - printk("i2c-algo-pcf.o:1 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + printk("i2c-algo-pcf.o:1 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); if ( 0 != getsda(adap) ) { printk("i2c-algo-pcf.o: %s SDA stuck high!\n",name); sdahi(adap); @@ -243,18 +208,21 @@ goto bailout; } sdahi(adap); - printk("i2c-algo-pcf.o:2 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + printk("i2c-algo-pcf.o:2 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); if ( 0 == getsda(adap) ) { printk("i2c-algo-pcf.o: %s SDA stuck low!\n",name); sdahi(adap); goto bailout; } if ( 0 == getscl(adap) ) { - printk("i2c-algo-pcf.o: %s SCL unexpected low while SDA high!\n",adap->name); + printk("i2c-algo-pcf.o: %s SCL unexpected low while SDA high!\n", + adap->name); goto bailout; } scllo(adap); - printk("i2c-algo-pcf.o:3 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + printk("i2c-algo-pcf.o:3 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); if ( 0 != getscl(adap) ) { printk("i2c-algo-pcf.o: %s SCL stuck high!\n",name); sclhi(adap); @@ -266,7 +234,8 @@ goto bailout; } sclhi(adap); - printk("i2c-algo-pcf.o:4 scl: %d sda: %d \n",getscl(adap),getsda(adap)); + printk("i2c-algo-pcf.o:4 scl: %d sda: %d \n",getscl(adap), + getsda(adap)); if ( 0 == getscl(adap) ) { printk("i2c-algo-pcf.o: %s SCL stuck low!\n",name); sclhi(adap); @@ -293,99 +262,99 @@ static inline int try_address(struct i2c_algo_pcf_data *adap, unsigned char addr, int retries) { - int i, status, ret = -1; - for (i=0;i= 0) { - if ((status && I2C_PCF_LRB) == 0) { - i2c_stop(adap); - break; /* success! */ - } - } - i2c_stop(adap); - udelay(adap->udelay); - } - DEB2(if (i) printk("i2c-algo-pcf.o: needed %d retries for %d\n",i,addr)); - return ret; + int i, status, ret = -1; + for (i=0;i= 0) { + if ((status && I2C_PCF_LRB) == 0) { + i2c_stop(adap); + break; /* success! */ + } + } + i2c_stop(adap); + udelay(adap->udelay); + } + DEB2(if (i) printk("i2c-algo-pcf.o: needed %d retries for %d\n",i, + addr)); + return ret; } -static int pcf_sendbytes(struct i2c_adapter *i2c_adap,const char *buf, int count) -{ - struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; - int wrcount, status, timeout; - - for (wrcount=0; wrcountname, buf[wrcount]&0xff)); - i2c_outb(adap, buf[wrcount]); - timeout = wait_for_pin(adap, &status); - if (timeout) { - printk("i2c-algo-pcf.o: %s i2c_write: error - timeout.\n", - i2c_adap->name); - i2c_stop(adap); - return -EREMOTEIO; /* got a better one ?? */ - } - if (status & I2C_PCF_LRB) { - printk("i2c-algo-pcf.o: %s i2c_write: error - no ack.\n", - i2c_adap->name); - i2c_stop(adap); - return -EREMOTEIO; /* got a better one ?? */ - } - } - return (wrcount); +static int pcf_sendbytes(struct i2c_adapter *i2c_adap,const char *buf, + int count) +{ + struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; + int wrcount, status, timeout; + + for (wrcount=0; wrcountname, buf[wrcount]&0xff)); + i2c_outb(adap, buf[wrcount]); + timeout = wait_for_pin(adap, &status); + if (timeout) { + printk("i2c-algo-pcf.o: %s i2c_write: error - timeout.\n", + i2c_adap->name); + i2c_stop(adap); + return -EREMOTEIO; /* got a better one ?? */ + } + if (status & I2C_PCF_LRB) { + printk("i2c-algo-pcf.o: %s i2c_write: error - no ack.\n", + i2c_adap->name); + i2c_stop(adap); + return -EREMOTEIO; /* got a better one ?? */ + } + } + return (wrcount); } static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count) { - int rdcount=0, i, status, timeout, dummy=1; - struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; + int rdcount=0, i, status, timeout, dummy=1; + struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; - for (i=0; iflags; unsigned char addr; int ret; if ( (flags & I2C_M_TEN) ) { /* a ten bit address */ - addr = 0xf0 | (( msg->addr >> 7) & 0x03); + addr = 0xf0 | (( msg->addr >> 7) & 0x03); DEB2(printk("addr0: %d\n",addr)); /* try extended address code...*/ ret = try_address(adap, addr, retries); @@ -414,6 +383,8 @@ addr = ( msg->addr << 1 ); if (flags & I2C_M_RD ) addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR ) + addr ^= 1; i2c_outb(adap, addr); } return 0; @@ -423,71 +394,50 @@ struct i2c_msg msgs[], int num) { - struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; - struct i2c_msg *pmsg; - int i, ret, timeout, status; - - timeout = wait_for_bb(adap); - if (timeout) { - DEB2(printk("i2c-algo-pcf.o: Timeout waiting for BB in pcf_xfer\n");) - return -EIO; - } - pmsg = &msgs[0]; - ret = pcf_doAddress(adap, pmsg, i2c_adap->retries); - i2c_start(adap); - - for (i=0; iflags & I2C_M_RD ) { - /* read bytes into buffer*/ - ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len); - DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret)); - } else { - /* write bytes from buffer */ - ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len); - DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret)); - } - if (i == (num-1)) { - i2c_stop(adap); - } - else { - i2c_repstart(adap); - } - if (pmsg->flags & I2C_M_RD ) { - pmsg->buf[pmsg->len-1] = i2c_inb(adap); - } - if (i != (num-1)) { - pmsg = &msgs[0]; - ret = pcf_doAddress(adap, pmsg, i2c_adap->retries); - timeout = wait_for_pin(adap, &status); - if (timeout) { - DEB2(printk("i2c-algo-pcf.o: Timeout waiting for PIN(2) in pcf_xfer\n");) - return (-EREMOTEIO); - } - if (status & I2C_PCF_LRB) { - i2c_stop(adap); - DEB2(printk("i2c-algo-pcf.o: No LRB(2) in pcf_xfer\n");) - return (-EREMOTEIO); - } - } - } - return (num); + struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; + struct i2c_msg *pmsg; + int i, ret, timeout, status; + + timeout = wait_for_bb(adap); + if (timeout) { + DEB2(printk("i2c-algo-pcf.o: Timeout waiting for BB in pcf_xfer\n");) + return -EIO; + } + i2c_start(adap); + + for (i=0; iflags & I2C_M_NOSTART)) { + if (i) + i2c_repstart(adap); + ret = pcf_doAddress(adap, pmsg, i2c_adap->retries); + timeout = wait_for_pin(adap, &status); + if (timeout) { + DEB2(printk("i2c-algo-pcf.o: Timeout waiting for PIN(1) in pcf_xfer\n");) + return (-EREMOTEIO); + } + if (status & I2C_PCF_LRB) { + i2c_stop(adap); + DEB2(printk("i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");) + return (-EREMOTEIO); + } + } + DEB3(printk("i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", + i, msgs[i].addr, msgs[i].flags, msgs[i].len);) + if (pmsg->flags & I2C_M_RD ) { + /* read bytes into buffer*/ + ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len); + DEB2(printk("i2c-algo-pcf.o: read %d bytes.\n",ret)); + } else { + /* write bytes from buffer */ + ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len); + DEB2(printk("i2c-algo-pcf.o: wrote %d bytes.\n",ret)); + } + } + i2c_stop(adap); + return (num); } - static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg) { @@ -496,7 +446,8 @@ static u32 pcf_func(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | + I2C_FUNC_PROTOCOL_MANGLING; } /* -----exported algorithm data: ------------------------------------- */ @@ -509,7 +460,7 @@ NULL, /* slave_xmit */ NULL, /* slave_recv */ algo_control, /* ioctl */ - pcf_func, /* functionality */ + pcf_func, /* functionality */ }; /* @@ -526,7 +477,8 @@ return -ENODEV; } - DEB2(printk("i2c-algo-pcf.o: hw routines for %s registered.\n",adap->name)); + DEB2(printk("i2c-algo-pcf.o: hw routines for %s registered.\n", + adap->name)); /* register new adapter to i2c module... */ @@ -545,20 +497,21 @@ /* scan bus */ if (pcf_scan) { - printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n", adap->name); - for (i = 0x00; i < 0xff; i+=2) { - i2c_outb(pcf_adap, i); - i2c_start(pcf_adap); - if ((wait_for_pin(pcf_adap, &status) >= 0) && - ((status && I2C_PCF_LRB) == 0)) { - printk("(%02x)",i>>1); - } else { - printk("."); - } - i2c_stop(pcf_adap); - udelay(pcf_adap->udelay); - } - printk("\n"); + printk(KERN_INFO " i2c-algo-pcf.o: scanning bus %s.\n", + adap->name); + for (i = 0x00; i < 0xff; i+=2) { + i2c_outb(pcf_adap, i); + i2c_start(pcf_adap); + if ((wait_for_pin(pcf_adap, &status) >= 0) && + ((status && I2C_PCF_LRB) == 0)) { + printk("(%02x)",i>>1); + } else { + printk("."); + } + i2c_stop(pcf_adap); + udelay(pcf_adap->udelay); + } + printk("\n"); } return 0; } @@ -577,7 +530,7 @@ int __init i2c_algo_pcf_init (void) { - printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n"); + printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n"); return 0; } @@ -595,7 +548,8 @@ MODULE_PARM_DESC(pcf_test, "Test if the I2C bus is available"); MODULE_PARM_DESC(pcf_scan, "Scan for active chips on the bus"); -MODULE_PARM_DESC(i2c_debug,"debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); int init_module(void) diff -u --recursive --new-file v2.3.42/linux/drivers/i2c/i2c-core.c linux/drivers/i2c/i2c-core.c --- v2.3.42/linux/drivers/i2c/i2c-core.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/i2c/i2c-core.c Wed Feb 9 18:48:03 2000 @@ -20,7 +20,7 @@ /* With some changes from Kyösti Mälkki . All SMBus-related things are written by Frodo Looijaard */ -/* $Id: i2c-core.c,v 1.48 2000/01/24 21:41:19 frodo Exp $ */ +/* $Id: i2c-core.c,v 1.50 2000/02/02 23:29:54 frodo Exp $ */ #include #include @@ -98,8 +98,7 @@ /* To implement the dynamic /proc/bus/i2c-? files, we need our own implementation of the read hook */ static struct file_operations i2cproc_operations = { - NULL, - i2cproc_bus_read, + read: i2cproc_bus_read, }; static struct inode_operations i2cproc_inode_operations = { @@ -475,38 +474,58 @@ struct inode * inode = file->f_dentry->d_inode; char *kbuf; struct i2c_client *client; - int i,j,len=0; + int i,j,k,order_nr,len=0,len_total; + int order[I2C_CLIENT_MAX]; if (count < 0) - return -EINVAL; - if (count > 4000) - count = 4000; + return -EINVAL; + len_total = file->f_pos + count; + /* Too bad if this gets longer (unlikely) */ + if (len_total > 4000) + len_total = 4000; for (i = 0; i < I2C_ADAP_MAX; i++) if (adapters[i]->inode == inode->i_ino) { /* We need a bit of slack in the kernel buffer; this makes the sprintf safe. */ if (! (kbuf = kmalloc(count + 80,GFP_KERNEL))) return -ENOMEM; - for (j = 0; j < I2C_CLIENT_MAX; j++) - if ((client = adapters[i]->clients[j])) - /* Filter out dummy clients */ - if (client->driver->id != I2C_DRIVERID_I2CDEV) - len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", - client->addr, - client->name,client->driver->name); - if (file->f_pos+len > count) - len = count - file->f_pos; - len = len - file->f_pos; - if (len < 0) - len = 0; - if (copy_to_user (buf,kbuf+file->f_pos, - len)) { - kfree(kbuf); - return -EFAULT; - } - file->f_pos += len; - kfree(kbuf); - return len; + /* Order will hold the indexes of the clients + sorted by address */ + order_nr=0; + for (j = 0; j < I2C_CLIENT_MAX; j++) { + if ((client = adapters[i]->clients[j]) && + (client->driver->id != I2C_DRIVERID_I2CDEV)) { + for(k = order_nr; + (k > 0) && + adapters[i]->clients[order[k-1]]-> + addr > client->addr; + k--) + order[k] = order[k-1]; + order[k] = j; + order_nr++; + } + } + + + for (j = 0; (j < order_nr) && (len < len_total); j++) { + client = adapters[i]->clients[order[j]]; + len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", + client->addr, + client->name, + client->driver->name); + } + len = len - file->f_pos; + if (len > count) + len = count; + if (len < 0) + len = 0; + if (copy_to_user (buf,kbuf+file->f_pos, len)) { + kfree(kbuf); + return -EFAULT; + } + file->f_pos += len; + kfree(kbuf); + return len; } return -ENOENT; } diff -u --recursive --new-file v2.3.42/linux/drivers/i2c/i2c-dev.c linux/drivers/i2c/i2c-dev.c --- v2.3.42/linux/drivers/i2c/i2c-dev.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/i2c/i2c-dev.c Wed Feb 9 11:42:35 2000 @@ -74,16 +74,12 @@ static int i2cdev_cleanup(void); static struct file_operations i2cdev_fops = { - i2cdev_lseek, - i2cdev_read, - i2cdev_write, - NULL, /* i2cdev_readdir */ - NULL, /* i2cdev_select */ - i2cdev_ioctl, - NULL, /* i2cdev_mmap */ - i2cdev_open, - NULL, /* i2cdev_flush */ - i2cdev_release, + llseek: i2cdev_lseek, + read: i2cdev_read, + write: i2cdev_write, + ioctl: i2cdev_ioctl, + open: i2cdev_open, + release: i2cdev_release, }; #define I2CDEV_ADAPS_MAX I2C_ADAP_MAX diff -u --recursive --new-file v2.3.42/linux/drivers/i2c/i2c-elv.c linux/drivers/i2c/i2c-elv.c --- v2.3.42/linux/drivers/i2c/i2c-elv.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/i2c/i2c-elv.c Wed Feb 9 18:48:03 2000 @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ /* i2c-elv.c i2c-hw access for philips style parallel port adapters */ /* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-99 Simon G. Vogl +/* Copyright (C) 1995-2000 Simon G. Vogl 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 @@ -16,39 +16,21 @@ 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. */ -/* ------------------------------------------------------------------------- +/* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-elv.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-elv.c,v 1.16 2000/01/18 23:54:07 frodo Exp $ */ #include #include #include #include #include -#if LINUX_VERSION_CODE >= 0x020135 #include -#else -#define __init -#endif - -/* 2.0.0 kernel compatibility */ -#if LINUX_VERSION_CODE < 0x020100 -#define MODULE_AUTHOR(noone) -#define MODULE_DESCRIPTION(none) -#define MODULE_PARM(no,param) -#define MODULE_PARM_DESC(no,description) -#define EXPORT_SYMBOL(noexport) -#define EXPORT_NO_SYMBOLS -#endif -#if LINUX_VERSION_CODE >= 0x020100 -# include -#else -# include -#endif +#include #include #include @@ -66,11 +48,11 @@ #define DEBE(x) x /* error messages */ #define DEBINIT(x) x /* detection status messages */ -/* --- Convenience defines for the parallel port: */ -#define BASE (unsigned int)(data) -#define DATA BASE /* Centronics data port */ -#define STAT (BASE+1) /* Centronics status port */ -#define CTRL (BASE+2) /* Centronics control port */ +/* --- Convenience defines for the parallel port: */ +#define BASE (unsigned int)(data) +#define DATA BASE /* Centronics data port */ +#define STAT (BASE+1) /* Centronics status port */ +#define CTRL (BASE+2) /* Centronics control port */ /* ----- local functions ---------------------------------------------- */ @@ -127,8 +109,8 @@ request_region(base,(base == 0x3bc)? 3 : 8, "i2c (ELV adapter)"); PortData = 0; - bit_elv_setsda((void*)base,1); - bit_elv_setscl((void*)base,1); + bit_elv_setsda((void*)base,1); + bit_elv_setscl((void*)base,1); } return 0; } @@ -140,7 +122,7 @@ static int bit_elv_reg(struct i2c_client *client) { - return 0; + return 0; } static int bit_elv_unreg(struct i2c_client *client) @@ -151,14 +133,14 @@ static void bit_elv_inc_use(struct i2c_adapter *adap) { #ifdef MODULE - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; #endif } static void bit_elv_dec_use(struct i2c_adapter *adap) { #ifdef MODULE - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; #endif } @@ -172,7 +154,7 @@ bit_elv_setscl, bit_elv_getsda, bit_elv_getscl, - 80, 80, 100, /* waits, timeout */ + 80, 80, 100, /* waits, timeout */ }; static struct i2c_adapter bit_elv_ops = { @@ -186,30 +168,30 @@ bit_elv_unreg, }; -int __init i2c_bitelv_init(void) +int __init i2c_bitelv_init(void) { printk("i2c-elv.o: i2c ELV parallel port adapter module\n"); - if (base==0) { - /* probe some values */ - base=DEFAULT_BASE; - bit_elv_data.data=(void*)DEFAULT_BASE; - if (bit_elv_init()==0) { - if(i2c_bit_add_bus(&bit_elv_ops) < 0) + if (base==0) { + /* probe some values */ + base=DEFAULT_BASE; + bit_elv_data.data=(void*)DEFAULT_BASE; + if (bit_elv_init()==0) { + if(i2c_bit_add_bus(&bit_elv_ops) < 0) return -ENODEV; - } else { - return -ENODEV; - } - } else { - bit_elv_ops.data=(void*)base; - if (bit_elv_init()==0) { - if(i2c_bit_add_bus(&bit_elv_ops) < 0) + } else { + return -ENODEV; + } + } else { + bit_elv_ops.data=(void*)base; + if (bit_elv_init()==0) { + if(i2c_bit_add_bus(&bit_elv_ops) < 0) return -ENODEV; - } else { - return -ENODEV; - } - } - printk("i2c-elv.o: found device at %#x.\n",base); - return 0; + } else { + return -ENODEV; + } + } + printk("i2c-elv.o: found device at %#x.\n",base); + return 0; } @@ -224,13 +206,13 @@ int init_module(void) { - return i2c_bitelv_init(); + return i2c_bitelv_init(); } void cleanup_module(void) { - i2c_bit_del_bus(&bit_elv_ops); - bit_elv_exit(); + i2c_bit_del_bus(&bit_elv_ops); + bit_elv_exit(); } #endif diff -u --recursive --new-file v2.3.42/linux/drivers/i2c/i2c-philips-par.c linux/drivers/i2c/i2c-philips-par.c --- v2.3.42/linux/drivers/i2c/i2c-philips-par.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/i2c/i2c-philips-par.c Wed Feb 9 18:48:03 2000 @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ /* i2c-philips-par.c i2c-hw access for philips style parallel port adapters */ /* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-99 Simon G. Vogl +/* Copyright (C) 1995-2000 Simon G. Vogl 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 @@ -16,34 +16,20 @@ 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. */ -/* ------------------------------------------------------------------------- +/* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* $Id: i2c-philips-par.c,v 1.12 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-philips-par.c,v 1.16 2000/01/18 23:54:07 frodo Exp $ */ #include #include #include -#if LINUX_VERSION_CODE >= 0x020135 #include -#else -#define __init -#endif #include #include -/* 2.0.0 kernel compatibility */ -#if LINUX_VERSION_CODE < 0x020100 -#define MODULE_AUTHOR(noone) -#define MODULE_DESCRIPTION(none) -#define MODULE_PARM(no,param) -#define MODULE_PARM_DESC(no,description) -#define EXPORT_SYMBOL(noexport) -#define EXPORT_NO_SYMBOLS -#endif - #include #include @@ -147,12 +133,12 @@ static void bit_lp_inc_use(struct i2c_adapter *adap) { - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; } static void bit_lp_dec_use(struct i2c_adapter *adap) { - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; } /* ------------------------------------------------------------------------ @@ -183,7 +169,7 @@ int __init i2c_bitlp_init(void) { - printk("i2c-philips-par.o: i2c Philips parallel port adapter module\n"); + printk("i2c-philips-par.o: i2c Philips parallel port adapter module\n"); if (base==0) { /* probe some values */ base=DEFAULT_BASE; diff -u --recursive --new-file v2.3.42/linux/drivers/i2c/i2c-velleman.c linux/drivers/i2c/i2c-velleman.c --- v2.3.42/linux/drivers/i2c/i2c-velleman.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/i2c/i2c-velleman.c Wed Feb 9 18:48:03 2000 @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ /* i2c-velleman.c i2c-hw access for Velleman K9000 adapters */ /* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-96 Simon G. Vogl +/* Copyright (C) 1995-96, 2000 Simon G. Vogl 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 @@ -16,32 +16,18 @@ 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. */ -/* ------------------------------------------------------------------------- +/* ------------------------------------------------------------------------- */ -/* $Id: i2c-velleman.c,v 1.14 1999/12/21 23:45:58 frodo Exp $ */ +/* $Id: i2c-velleman.c,v 1.19 2000/01/24 02:06:33 mds Exp $ */ #include #include #include -#if LINUX_VERSION_CODE >= 0x020135 #include -#else -#define __init -#endif #include /* for 2.0 kernels to get NULL */ #include /* for 2.0 kernels to get ENODEV */ #include -/* 2.0.0 kernel compatibility */ -#if LINUX_VERSION_CODE < 0x020100 -#define MODULE_AUTHOR(noone) -#define MODULE_DESCRIPTION(none) -#define MODULE_PARM(no,param) -#define MODULE_PARM_DESC(no,description) -#define EXPORT_SYMBOL(noexport) -#define EXPORT_NO_SYMBOLS -#endif - #include #include @@ -55,7 +41,7 @@ #define I2C_SCL 0x08 /* ctrl bit 3 (inv) */ #define I2C_SDAIN 0x10 /* stat bit 4 */ -#define I2C_SCLIN 0x08 /* ctrl bit 3 (inv) (reads own output) */ +#define I2C_SCLIN 0x08 /* ctrl bit 3 (inv)(reads own output)*/ #define I2C_DMASK 0xfd #define I2C_CMASK 0xf7 @@ -105,7 +91,8 @@ static int bit_velle_init(void) { if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { - DEBE(printk("i2c-velleman.o: Port %#x already in use.\n", base)); + DEBE(printk("i2c-velleman.o: Port %#x already in use.\n", + base)); return -ENODEV; } else { request_region(base, (base == 0x3bc)? 3 : 8, @@ -173,7 +160,7 @@ int __init i2c_bitvelle_init(void) { - printk("i2c-velleman.o: i2c Velleman K8000 adapter module\n"); + printk("i2c-velleman.o: i2c Velleman K8000 adapter module\n"); if (base==0) { /* probe some values */ base=DEFAULT_BASE; diff -u --recursive --new-file v2.3.42/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c --- v2.3.42/linux/drivers/i2o/i2o_config.c Tue Jan 11 22:31:40 2000 +++ linux/drivers/i2o/i2o_config.c Wed Feb 9 11:42:35 2000 @@ -881,18 +881,13 @@ static struct file_operations config_fops = { - cfg_llseek, - cfg_read, - cfg_write, - NULL, - NULL /*cfg_poll*/, - cfg_ioctl, - NULL, /* No mmap */ - cfg_open, - NULL, /* No flush */ - cfg_release, - NULL, - cfg_fasync + llseek: cfg_llseek, + read: cfg_read, + write: cfg_write, + ioctl: cfg_ioctl, + open: cfg_open, + release: cfg_release, + fasync: cfg_fasync, }; static struct miscdevice i2o_miscdev = { diff -u --recursive --new-file v2.3.42/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c --- v2.3.42/linux/drivers/ieee1394/pcilynx.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/pcilynx.c Wed Feb 9 11:42:35 2000 @@ -681,12 +681,12 @@ static struct file_operations aux_ops = { - /* FIXME: should have custom llseek with bounds checking*/ - read: mem_read, - write: mem_write, - poll: aux_poll, - open: mem_open, - release: mem_release + /* FIXME: should have custom llseek with bounds checking */ + read: mem_read, + write: mem_write, + poll: aux_poll, + open: mem_open, + release: mem_release, }; diff -u --recursive --new-file v2.3.42/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.3.42/linux/drivers/isdn/avmb1/capi.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/isdn/avmb1/capi.c Wed Feb 9 11:42:35 2000 @@ -511,18 +511,13 @@ static struct file_operations capi_fops = { - capi_llseek, - capi_read, - capi_write, - NULL, /* capi_readdir */ - capi_poll, - capi_ioctl, - NULL, /* capi_mmap */ - capi_open, - NULL, /* capi_flush */ - capi_release, - NULL, /* capi_fsync */ - NULL, /* capi_fasync */ + llseek: capi_llseek, + read: capi_read, + write: capi_write, + poll: capi_poll, + ioctl: capi_ioctl, + open: capi_open, + release: capi_release, }; /* -------- /proc functions ----------------------------------- */ diff -u --recursive --new-file v2.3.42/linux/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c --- v2.3.42/linux/drivers/isdn/divert/divert_procfs.c Tue Dec 7 09:32:43 1999 +++ linux/drivers/isdn/divert/divert_procfs.c Wed Feb 9 11:42:35 2000 @@ -279,17 +279,13 @@ static struct file_operations isdn_fops = { - isdn_divert_lseek, - isdn_divert_read, - isdn_divert_write, - NULL, /* isdn_readdir */ - isdn_divert_poll, /* isdn_poll */ - isdn_divert_ioctl, /* isdn_ioctl */ - NULL, /* isdn_mmap */ - isdn_divert_open, - NULL, /* flush */ - isdn_divert_close, - NULL /* fsync */ + llseek: isdn_divert_lseek, + read: isdn_divert_read, + write: isdn_divert_write, + poll: isdn_divert_poll, + ioctl: isdn_divert_ioctl, + open: isdn_divert_open, + release: isdn_divert_close, }; struct inode_operations divert_file_inode_operations = { diff -u --recursive --new-file v2.3.42/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.3.42/linux/drivers/isdn/isdn_common.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/isdn_common.c Wed Feb 9 11:42:35 2000 @@ -2024,17 +2024,13 @@ static struct file_operations isdn_fops = { - isdn_lseek, - isdn_read, - isdn_write, - NULL, /* isdn_readdir */ - isdn_poll, /* isdn_poll */ - isdn_ioctl, /* isdn_ioctl */ - NULL, /* isdn_mmap */ - isdn_open, - NULL, /* flush */ - isdn_close, - NULL /* fsync */ + llseek: isdn_lseek, + read: isdn_read, + write: isdn_write, + poll: isdn_poll, + ioctl: isdn_ioctl, + open: isdn_open, + release: isdn_close, }; char * diff -u --recursive --new-file v2.3.42/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile --- v2.3.42/linux/drivers/macintosh/Makefile Sat Oct 9 11:47:50 1999 +++ linux/drivers/macintosh/Makefile Mon Feb 7 09:51:43 2000 @@ -18,6 +18,10 @@ ifeq ($(CONFIG_PMAC_PBOOK),y) L_OBJS += mediabay.o +else + ifeq ($(CONFIG_MAC_FLOPPY),y) + L_OBJS += mediabay.o + endif endif ifeq ($(CONFIG_MAC_SERIAL),y) diff -u --recursive --new-file v2.3.42/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c --- v2.3.42/linux/drivers/macintosh/adb.c Sat Oct 9 11:47:50 1999 +++ linux/drivers/macintosh/adb.c Wed Feb 9 19:43:57 2000 @@ -247,6 +247,8 @@ switch (when) { case PBOOK_SLEEP_REQUEST: adb_got_sleep = 1; + if (adb_controller->autopoll) + adb_controller->autopoll(0); ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL); if (ret & NOTIFY_STOP_MASK) return PBOOK_SLEEP_REFUSE; @@ -262,6 +264,7 @@ break; case PBOOK_WAKE: adb_reset_bus(); + adb_got_sleep = 0; break; } return PBOOK_SLEEP_OK; @@ -271,15 +274,21 @@ int adb_reset_bus(void) { - int ret, devs; + int ret, nret, devs; unsigned long flags; if (adb_controller == NULL) return -ENXIO; - ret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL); - if (ret & NOTIFY_STOP_MASK) + if (adb_controller->autopoll) + adb_controller->autopoll(0); + + nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL); + if (nret & NOTIFY_STOP_MASK) { + if (adb_controller->autopoll) + adb_controller->autopoll(devs); return -EBUSY; + } save_flags(flags); cli(); @@ -291,18 +300,17 @@ else ret = 0; - if (!ret) - { + if (!ret) { devs = adb_scan_bus(); if (adb_controller->autopoll) adb_controller->autopoll(devs); } - ret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL); - if (ret & NOTIFY_STOP_MASK) + nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL); + if (nret & NOTIFY_STOP_MASK) return -EBUSY; - return 1; + return ret; } void @@ -383,6 +391,12 @@ int i, id; static int dump_adb_input = 0; + /* We skip keystrokes and mouse moves when the sleep process + * has been started. We stop autopoll, but this is another security + */ + if (adb_got_sleep) + return; + id = buf[0] >> 4; if (dump_adb_input) { printk(KERN_INFO "adb packet: "); @@ -403,12 +417,8 @@ if (adb_handler[address].handler_id == new_id) return 1; - adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, - ADB_READREG(address,3)); - if (req.reply_len < 2) - return 0; adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(address, 3), req.reply[1] & 0xF0, new_id); + ADB_WRITEREG(address, 3), address | 0x20, new_id); adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, ADB_READREG(address, 3)); if (req.reply_len < 2) @@ -611,10 +621,11 @@ /* Special case for ADB_BUSRESET request, all others are sent to the controller */ if ((req->data[0] == ADB_PACKET)&&(count > 1) - &&(req->data[1] == ADB_BUSRESET)) + &&(req->data[1] == ADB_BUSRESET)) { ret = adb_reset_bus(); - else - { + atomic_dec(&state->n_pending); + goto out; + } else { req->reply_expected = ((req->data[1] & 0xc) == 0xc); if (adb_controller && adb_controller->send_request) @@ -635,16 +646,11 @@ } static struct file_operations adb_fops = { - adb_lseek, - adb_read, - adb_write, - NULL, /* no readdir */ - NULL, /* no poll yet */ - NULL, /* no ioctl yet */ - NULL, /* no mmap */ - adb_open, - NULL, /* flush */ - adb_release + llseek: adb_lseek, + read: adb_read, + write: adb_write, + open: adb_open, + release: adb_release, }; void adbdev_init() diff -u --recursive --new-file v2.3.42/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c --- v2.3.42/linux/drivers/macintosh/mac_keyb.c Fri Oct 15 15:25:13 1999 +++ linux/drivers/macintosh/mac_keyb.c Wed Feb 9 19:43:47 2000 @@ -16,13 +16,15 @@ * * - Standard 1 button mouse * - All standard Apple Extended protocol (handler ID 4) - * mice & trackballs + * - mouseman and trackman mice & trackballs * - PowerBook Trackpad (default setup: enable tapping) * - MicroSpeed mouse & trackball (needs testing) * - CH Products Trackball Pro (needs testing) * - Contour Design (Contour Mouse) * - Hunter digital (NoHandsMouse) * - Kensignton TurboMouse 5 (needs testing) + * - Mouse Systems A3 mice and trackballs + * - MacAlly 2-buttons mouse (needs testing) * * To do: * @@ -66,10 +68,10 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* esc...option */ - 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fn, num lock */ + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* fn, num lock */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* R modifiers */ }; /* Simple translation table for the SysRq keys */ @@ -239,6 +241,7 @@ static void init_trackball(int id); static void init_turbomouse(int id); static void init_microspeed(int id); +static void init_ms_a3(int id); #ifdef CONFIG_ADBMOUSE /* XXX: Hook for mouse driver */ @@ -268,6 +271,8 @@ #define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */ #define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */ #define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */ +#define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */ +#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */ static int adb_mouse_kinds[16]; @@ -484,6 +489,19 @@ data[3] = byyy bxxx Third button and fourth button. Y is additional high bits of y-axis motion. XY is additional high bits of x-axis motion. + + MacAlly 2-button mouse protocol. + + For MacAlly 2-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Right button and y-axis motion. + data[3] = ???? ???? unknown + data[4] = ???? ???? unknown + */ struct kbd_struct *kbd; @@ -510,6 +528,16 @@ data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7); data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6); break; + case ADBMOUSE_MS_A3: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = ((data[3] & 0x04) << 5); + break; + case ADBMOUSE_MACALLY2: + data[3] = (data[2] & 0x80) ? 0x80 : 0x00; + data[2] |= 0x80; /* Right button is mapped as button 3 */ + nb=4; + break; } if (adb_mouse_interrupt_hook) @@ -642,7 +670,6 @@ static void real_mackbd_leds(unsigned char leds, int device) { - if (led_request.complete) { adb_request(&led_request, leds_done, 0, 3, ADB_WRITEREG(device, KEYB_LEDREG), 0xff, @@ -715,10 +742,18 @@ static int adb_message_handler(struct notifier_block *this, unsigned long code, void *x) { + unsigned long flags; + switch (code) { case ADB_MSG_PRE_RESET: case ADB_MSG_POWERDOWN: - /* Add unregister_keyboard when merging with Paul Mackerras */ + /* Stop the repeat timer. Autopoll is already off at this point */ + save_flags(flags); + cli(); + del_timer(&repeat_timer); + restore_flags(flags); + + /* Stop pending led requests */ while(!led_request.complete) adb_poll(); break; @@ -753,9 +788,12 @@ /* Enable full feature set of the keyboard ->get it to send separate codes for left and right shift, control, option keys */ +#if 0 /* handler 5 doesn't send separate codes for R modifiers */ if (adb_try_handler_change(id, 5)) printk("ADB keyboard at %d, handler set to 5\n", id); - else if (adb_try_handler_change(id, 3)) + else +#endif + if (adb_try_handler_change(id, 3)) printk("ADB keyboard at %d, handler set to 3\n", id); else printk("ADB keyboard at %d, handler 1\n", id); @@ -769,10 +807,6 @@ printk("ADB mouse at %d, handler set to 4", id); adb_mouse_kinds[id] = ADBMOUSE_EXTENDED; } - else if (adb_try_handler_change(id, 2)) { - printk("ADB mouse at %d, handler set to 2", id); - adb_mouse_kinds[id] = ADBMOUSE_STANDARD_200; - } else if (adb_try_handler_change(id, 0x2F)) { printk("ADB mouse at %d, handler set to 0x2F", id); adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED; @@ -789,6 +823,14 @@ printk("ADB mouse at %d, handler set to 0x5F", id); adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED; } + else if (adb_try_handler_change(id, 3)) { + printk("ADB mouse at %d, handler set to 3", id); + adb_mouse_kinds[id] = ADBMOUSE_MS_A3; + } + else if (adb_try_handler_change(id, 2)) { + printk("ADB mouse at %d, handler set to 2", id); + adb_mouse_kinds[id] = ADBMOUSE_STANDARD_200; + } else { printk("ADB mouse at %d, handler 1", id); adb_mouse_kinds[id] = ADBMOUSE_STANDARD_100; @@ -797,6 +839,8 @@ if ((adb_mouse_kinds[id] == ADBMOUSE_TRACKBALLPRO) || (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) { init_microspeed(id); + } else if (adb_mouse_kinds[id] == ADBMOUSE_MS_A3) { + init_ms_a3(id); } else if (adb_mouse_kinds[id] == ADBMOUSE_EXTENDED) { /* * Register 1 is usually used for device @@ -808,7 +852,8 @@ ADB_READREG(id, 1)); if ((req.reply_len) && - (req.reply[1] == 0x9a) && (req.reply[2] == 0x21)) + (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21) + || (req.reply[2] == 0x20))) init_trackball(id); else if ((req.reply_len >= 4) && (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && @@ -818,6 +863,14 @@ (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) && (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) init_turbomouse(id); + else if ((req.reply_len == 9) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) && + (req.reply[3] == 0x49) && (req.reply[4] == 0x54)){ + if (adb_try_handler_change(id, 0x42)) { + printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id); + adb_mouse_kinds[id] = ADBMOUSE_MACALLY2; + } + } } printk("\n"); } @@ -880,7 +933,7 @@ { struct adb_request req; - printk(" (trackball)"); + printk(" (trackman/mouseman)"); adb_mouse_kinds[id] = ADBMOUSE_TRACKBALL; @@ -920,13 +973,10 @@ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); - adb_request(&req, NULL, ADBREQ_SYNC, 3, - ADB_WRITEREG(id,3), 0x20 | id, 4); - - adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); adb_request(&req, NULL, ADBREQ_SYNC, 9, - ADB_WRITEREG(id,2), + ADB_WRITEREG(3,2), 0xe7, 0x8c, 0, @@ -936,10 +986,10 @@ 0xff, 0x94); - adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); adb_request(&req, NULL, ADBREQ_SYNC, 9, - ADB_WRITEREG(id,2), + ADB_WRITEREG(3,2), 0xa5, 0x14, 0, @@ -989,4 +1039,18 @@ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); } + +static void +init_ms_a3(int id) +{ + struct adb_request req; + + printk(" (Mouse Systems A3 Mouse, or compatible)"); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, 0x2), + 0x00, + 0x07); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + } diff -u --recursive --new-file v2.3.42/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.3.42/linux/drivers/macintosh/macserial.c Wed Oct 27 16:34:12 1999 +++ linux/drivers/macintosh/macserial.c Wed Feb 9 19:43:53 2000 @@ -8,7 +8,7 @@ * * Receive DMA code by Takashi Oe . * - * $Id: macserial.c,v 1.24.2.3 1999/09/10 02:05:58 paulus Exp $ + * $Id: macserial.c,v 1.24.2.4 1999/10/19 04:36:42 paulus Exp $ */ #include @@ -130,6 +130,22 @@ #define _INLINE_ inline +#ifdef SERIAL_DEBUG_OPEN +#define OPNDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg) +#else +#define OPNDBG(fmt, arg...) do { } while (0) +#endif +#ifdef SERIAL_DEBUG_POWER +#define PWRDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg) +#else +#define PWRDBG(fmt, arg...) do { } while (0) +#endif +#ifdef SERIAL_DEBUG_BAUDS +#define BAUDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg) +#else +#define BAUDBG(fmt, arg...) do { } while (0) +#endif + static void probe_sccs(void); static void change_speed(struct mac_serial *info, struct termios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); @@ -318,7 +334,7 @@ * to it. - paulus) */ for (i = 200; i > 0; --i) - if (ld_le32(&dma->control) & RUN) + if (ld_le32(&dma->status) & RUN) udelay(1); } @@ -718,14 +734,10 @@ { int delay; -#ifdef SERIAL_DEBUG_OPEN - printk("startup() (ttyS%d, irq %d)\n", info->line, info->irq); -#endif + OPNDBG("startup() (ttyS%d, irq %d)\n", info->line, info->irq); if (info->flags & ZILOG_INITIALIZED) { -#ifdef SERIAL_DEBUG_OPEN - printk(" -> already inited\n"); -#endif + OPNDBG(" -> already inited\n"); return 0; } @@ -735,17 +747,13 @@ return -ENOMEM; } -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq); -#endif + OPNDBG("starting up ttyS%d (irq %d)...\n", info->line, info->irq); delay = set_scc_power(info, 1); setup_scc(info); -#ifdef SERIAL_DEBUG_OPEN - printk("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq); -#endif + OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq); info->flags |= ZILOG_INITIALIZED; enable_irq(info->irq); @@ -951,9 +959,7 @@ { unsigned long flags; -#ifdef SERIAL_DEBUG_OPEN - printk("setting up ttys%d SCC...\n", info->line); -#endif + OPNDBG("setting up ttys%d SCC...\n", info->line); save_flags(flags); cli(); /* Disable interrupts */ @@ -1050,16 +1056,11 @@ */ static void shutdown(struct mac_serial * info) { -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....\n", info->line, + OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line, info->irq); -#endif if (!(info->flags & ZILOG_INITIALIZED)) { -#ifdef SERIAL_DEBUG_OPEN - printk("(already shutdown)\n"); -#endif - + OPNDBG("(already shutdown)\n"); return; } @@ -1125,24 +1126,27 @@ ones, at least whe not using the modem, this should be tested. */ if (state) { -#ifdef SERIAL_DEBUG_POWER - printk(KERN_INFO "ttyS%02d: powering up hardware\n", info->line); -#endif + PWRDBG("ttyS%02d: powering up hardware\n", info->line); if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) { - feature_clear(info->dev_node, FEATURE_Serial_reset); - mdelay(5); feature_set(info->dev_node, FEATURE_Serial_enable); + mdelay(10); + feature_set(info->dev_node, FEATURE_Serial_reset); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Serial_reset); + mdelay(10); } if (info->zs_chan_a == info->zs_channel) feature_set(info->dev_node, FEATURE_Serial_IO_A); else feature_set(info->dev_node, FEATURE_Serial_IO_B); - delay = 1; - + delay = 10; if (info->is_cobalt_modem){ - feature_set(info->dev_node, FEATURE_Modem_Reset); + mdelay(300); + feature_set(info->dev_node, FEATURE_Modem_power); mdelay(5); - feature_clear(info->dev_node, FEATURE_Modem_Reset); + feature_clear(info->dev_node, FEATURE_Modem_power); + mdelay(10); + feature_set(info->dev_node, FEATURE_Modem_power); delay = 2500; /* wait for 2.5s before using */ } #ifdef CONFIG_PMAC_PBOOK @@ -1150,33 +1154,11 @@ pmu_enable_irled(1); #endif /* CONFIG_PMAC_PBOOK */ } else { -#ifdef SERIAL_DEBUG_POWER - printk(KERN_INFO "ttyS%02d: shutting down hardware\n", info->line); -#endif -#ifdef CONFIG_KGDB - if (info->kgdb_channel) { -#ifdef SERIAL_DEBUG_POWER - printk(KERN_INFO " (canceled by KGDB)\n"); -#endif - return 0; - } -#endif -#ifdef CONFIG_XMON - if (!info->is_cobalt_modem) { -#ifdef SERIAL_DEBUG_POWER - printk(KERN_INFO " (canceled by XMON)\n"); -#endif - return 0; - } -#endif + PWRDBG("ttyS%02d: shutting down hardware\n", info->line); if (info->is_cobalt_modem) { -#ifdef SERIAL_DEBUG_POWER - printk(KERN_INFO "ttyS%02d: shutting down modem\n", info->line); -#endif - feature_set(info->dev_node, FEATURE_Modem_Reset); - mdelay(15); - feature_clear(info->dev_node, FEATURE_Modem_Reset); - mdelay(25); + PWRDBG("ttyS%02d: shutting down modem\n", info->line); + feature_clear(info->dev_node, FEATURE_Modem_power); + mdelay(10); } #ifdef CONFIG_PMAC_PBOOK if (info->is_pwbk_ir) @@ -1184,25 +1166,21 @@ #endif /* CONFIG_PMAC_PBOOK */ if (info->zs_chan_a == info->zs_channel) { -#ifdef SERIAL_DEBUG_POWER - printk(KERN_INFO "ttyS%02d: shutting down SCC channel A\n", info->line); -#endif + PWRDBG("ttyS%02d: shutting down SCC channel A\n", info->line); feature_clear(info->dev_node, FEATURE_Serial_IO_A); } else { -#ifdef SERIAL_DEBUG_POWER - printk(KERN_INFO "ttyS%02d: shutting down SCC channel B\n", info->line); -#endif + PWRDBG("ttyS%02d: shutting down SCC channel B\n", info->line); feature_clear(info->dev_node, FEATURE_Serial_IO_B); } /* XXX for now, shut down SCC core only on powerbooks */ if (is_powerbook && !(feature_test(info->dev_node, FEATURE_Serial_IO_A) || feature_test(info->dev_node, FEATURE_Serial_IO_B))) { -#ifdef SERIAL_DEBUG_POWER - printk(KERN_INFO "ttyS%02d: shutting down SCC core\n", info->line); -#endif + PWRDBG("ttyS%02d: shutting down SCC core\n", info->line); feature_set(info->dev_node, FEATURE_Serial_reset); - mdelay(10); + mdelay(15); + feature_clear(info->dev_node, FEATURE_Serial_reset); + mdelay(25); feature_clear(info->dev_node, FEATURE_Serial_enable); mdelay(5); } @@ -1249,9 +1227,7 @@ info->zs_baud = baud; info->clk_divisor = 16; -#ifdef SERIAL_DEBUG_BAUDS - printk("set speed to %d bds, ", baud); -#endif + BAUDBG("set speed to %d bds, ", baud); switch (baud) { case ZS_CLOCK/16: /* 230400 */ @@ -1278,34 +1254,26 @@ case CS5: info->curregs[3] |= Rx5; info->curregs[5] |= Tx5; -#ifdef SERIAL_DEBUG_BAUDS - printk("5 bits, "); -#endif + BAUDBG("5 bits, "); bits = 7; break; case CS6: info->curregs[3] |= Rx6; info->curregs[5] |= Tx6; -#ifdef SERIAL_DEBUG_BAUDS - printk("6 bits, "); -#endif + BAUDBG("6 bits, "); bits = 8; break; case CS7: info->curregs[3] |= Rx7; info->curregs[5] |= Tx7; -#ifdef SERIAL_DEBUG_BAUDS - printk("7 bits, "); -#endif + BAUDBG("7 bits, "); bits = 9; break; case CS8: default: /* defaults to 8 bits */ info->curregs[3] |= Rx8; info->curregs[5] |= Tx8; -#ifdef SERIAL_DEBUG_BAUDS - printk("8 bits, "); -#endif + BAUDBG("8 bits, "); bits = 10; break; } @@ -1316,21 +1284,15 @@ if (cflag & CSTOPB) { info->curregs[4] |= SB2; bits++; -#ifdef SERIAL_DEBUG_BAUDS - printk("2 stop, "); -#endif + BAUDBG("2 stop, "); } else { info->curregs[4] |= SB1; -#ifdef SERIAL_DEBUG_BAUDS - printk("1 stop, "); -#endif + BAUDBG("1 stop, "); } if (cflag & PARENB) { bits++; info->curregs[4] |= PAR_ENA; -#ifdef SERIAL_DEBUG_BAUDS - printk("parity, "); -#endif + BAUDBG("parity, "); } if (!(cflag & PARODD)) { info->curregs[4] |= PAR_EVEN; @@ -1360,9 +1322,8 @@ info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud); info->timeout += HZ/50+1; /* Add .02 seconds of slop */ -#ifdef SERIAL_DEBUG_BAUDS - printk("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ, (int)info->baud_base); -#endif + BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ, + (int)info->baud_base); /* Load up the new values */ load_zsregs(info->zs_channel, info->curregs); @@ -1823,9 +1784,7 @@ return; } -#ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", info->line, info->count); -#endif + OPNDBG("rs_close ttys%d, count = %d\n", info->line, info->count); if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty @@ -1861,9 +1820,7 @@ * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ -#ifdef SERIAL_DEBUG_OPEN - printk("waiting end of Tx... (timeout:%d)\n", info->closing_wait); -#endif + OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait); tty->closing = 1; if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) { restore_flags(flags); @@ -1887,9 +1844,7 @@ * Before we drop DTR, make sure the SCC transmitter * has completely drained. */ -#ifdef SERIAL_DEBUG_OPEN - printk("waiting end of Rx...\n"); -#endif + OPNDBG("waiting end of Rx...\n"); restore_flags(flags); rs_wait_until_sent(tty, info->timeout); save_flags(flags); cli(); @@ -2059,10 +2014,8 @@ */ retval = 0; add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", + OPNDBG("block_til_ready before block: ttys%d, count = %d\n", info->line, info->count); -#endif cli(); if (!tty_hung_up_p(filp)) info->count--; @@ -2095,10 +2048,8 @@ retval = -ERESTARTSYS; break; } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", + OPNDBG("block_til_ready blocking: ttys%d, count = %d\n", info->line, info->count); -#endif schedule(); } current->state = TASK_RUNNING; @@ -2106,10 +2057,8 @@ if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", + OPNDBG("block_til_ready after blocking: ttys%d, count = %d\n", info->line, info->count); -#endif if (retval) return retval; info->flags |= ZILOG_NORMAL_ACTIVE; @@ -2144,10 +2093,8 @@ #endif if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + OPNDBG("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->count); -#endif info->count++; tty->driver_data = info; @@ -2188,10 +2135,8 @@ retval = block_til_ready(tty, filp, info); if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", + OPNDBG("rs_open returning after block_til_ready with %d\n", retval); -#endif return retval; } @@ -2213,9 +2158,7 @@ info->session = current->session; info->pgrp = current->pgrp; -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open ttys%d successful...\n", info->line); -#endif + OPNDBG("rs_open ttys%d successful...\n", info->line); return 0; } @@ -2237,6 +2180,10 @@ struct device_node *ch = zss->dev_node; char *conn; int len; + struct slot_names_prop { + int count; + char name[1]; + } *slots; zss->irq = ch->intrs[0].line; zss->has_dma = 0; @@ -2262,6 +2209,10 @@ should do no harm anyway */ conn = get_property(ch, "AAPL,connector", &len); zss->is_pwbk_ir = conn && (strcmp(conn, "infrared") == 0); + /* 1999 Powerbook G3 has slot-names property instead */ + slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len); + if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0) + zss->is_pwbk_ir = 1; if (zss->has_dma) { zss->dma_priv = NULL; @@ -2506,16 +2457,13 @@ printk(" (powerbook IR)"); printk("\n"); +#ifndef CONFIG_XMON #ifdef CONFIG_KGDB - if (info->kgdb_channel) - continue; -#endif -#ifdef CONFIG_XMON - if (!info->is_cobalt_modem) - continue; -#endif + if (!info->kgdb_channel) +#endif /* CONFIG_KGDB */ /* By default, disable the port */ set_scc_power(info, 0); +#endif /* CONFIG_XMON */ } tmp_buf = 0; diff -u --recursive --new-file v2.3.42/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c --- v2.3.42/linux/drivers/macintosh/mediabay.c Fri Oct 15 15:25:13 1999 +++ linux/drivers/macintosh/mediabay.c Wed Feb 9 19:43:53 2000 @@ -38,6 +38,14 @@ #endif #undef MB_USE_INTERRUPTS +#undef MB_DEBUG +#define MB_IGNORE_SIGNALS + +#ifdef MB_DEBUG +#define MBDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg) +#else +#define MBDBG(fmt, arg...) do { } while (0) +#endif struct media_bay_hw { unsigned char b0; @@ -49,17 +57,16 @@ struct media_bay_info { volatile struct media_bay_hw* addr; int content_id; - int previous_id; - int ready; + int state; int last_value; int value_count; - int reset_timer; + int timer; struct device_node* dev_node; #ifdef CONFIG_BLK_DEV_IDE unsigned long cd_base; int cd_index; int cd_irq; - int cd_timer; + int cd_retry; #endif }; @@ -73,31 +80,79 @@ #ifdef CONFIG_BLK_DEV_IDE /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ +//#define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0xc0) == 0x40) #define MB_IDE_READY(i) ((inb(media_bays[i].cd_base + 0x70) & 0x80) == 0) #endif +/* Note: All delays are not in milliseconds and converted to HZ relative + * values by the macro below + */ +#define MS_TO_HZ(ms) ((ms * HZ) / 1000) + /* * Consider the media-bay ID value stable if it is the same for - * this many consecutive samples (at intervals of 1/HZ seconds). + * this number of milliseconds */ -#define MB_STABLE_COUNT 4 +#define MB_STABLE_DELAY 40 + +/* Wait after powering up the media bay this delay in ms + * timeout bumped for some powerbooks + */ +#define MB_POWER_DELAY 200 /* * Hold the media-bay reset signal true for this many ticks * after a device is inserted before releasing it. */ -#define MB_RESET_COUNT 40 +#define MB_RESET_DELAY 40 + +/* + * Wait this long after the reset signal is released and before doing + * further operations. After this delay, the IDE reset signal is released + * too for an IDE device + */ +#define MB_SETUP_DELAY 100 /* * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted - * (or until the device is ready) before registering the IDE interface. + * (or until the device is ready) before waiting for busy bit to disappear + */ +#define MB_IDE_WAIT 1000 + +/* + * Timeout waiting for busy bit of an IDE device to go down + */ +#define MB_IDE_TIMEOUT 5000 + +/* + * Max retries of the full power up/down sequence for an IDE device + */ +#define MAX_CD_RETRIES 3 + +/* + * States of a media bay */ -#define MB_IDE_WAIT 1500 +enum { + mb_empty = 0, /* Idle */ + mb_powering_up, /* power bit set, waiting MB_POWER_DELAY */ + mb_enabling_bay, /* enable bits set, waiting MB_RESET_DELAY */ + mb_resetting, /* reset bit unset, waiting MB_SETUP_DELAY */ + mb_ide_resetting, /* IDE reset bit unser, waiting MB_IDE_WAIT */ + mb_ide_waiting, /* Waiting for BUSY bit to go away until MB_IDE_TIMEOUT */ + mb_up, /* Media bay full */ + mb_powering_down /* Powering down (avoid too fast down/up) */ +}; static void poll_media_bay(int which); static void set_media_bay(int which, int id); +static void set_mb_power(int which, int onoff); +static void media_bay_step(int i); static int media_bay_task(void *); +#ifdef MB_USE_INTERRUPTS +static void media_bay_intr(int irq, void *devid, struct pt_regs *regs); +#endif + /* * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL * register is always set when there is something in the media bay. @@ -113,8 +168,7 @@ struct device_node *np; int n,i; - for (i=0; in_addrs == 0) continue; media_bays[n].addr = (volatile struct media_bay_hw *) ioremap(np->addrs[0].address, sizeof(struct media_bay_hw)); #ifdef MB_USE_INTERRUPTS - if (np->n_intrs == 0) - { + if (np->n_intrs == 0) { printk(KERN_ERR "media bay %d has no irq\n",n); continue; } - if (request_irq(np_intrs[0].line, media_bay_intr, 0, "Media bay", NULL)) - { - printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", irq, n); + if (request_irq(np->intrs[0].line, media_bay_intr, 0, "Media bay", (void *)n)) { + printk(KERN_ERR "Couldn't get IRQ %d for media bay %d\n", + np->intrs[0].line, n); continue; } #endif media_bay_count++; - set_media_bay(n, MB_CONTENTS(n)); - if (media_bays[n].content_id != MB_NO) { - feature_clear(media_bays[n].dev_node, FEATURE_Mediabay_reset); - udelay(500); - } - media_bays[n].ready = 1; - media_bays[n].previous_id = media_bays[n].content_id; - media_bays[n].reset_timer = 0; media_bays[n].dev_node = np; -#ifdef CONFIG_BLK_DEV_IDE - media_bays[n].cd_timer = 0; -#endif + + /* Force an immediate detect */ + set_mb_power(n,0); + mdelay(MB_POWER_DELAY); + out_8(&media_bays[n].addr->contents, 0x70); + mdelay(MB_STABLE_DELAY); + media_bays[n].content_id = MB_NO; + media_bays[n].last_value = MB_CONTENTS(n); + media_bays[n].value_count = MS_TO_HZ(MB_STABLE_DELAY); + media_bays[n].state = mb_empty; + do { + mdelay(1000/HZ); + media_bay_step(n); + } while((media_bays[n].state != mb_empty) && + (media_bays[n].state != mb_up)); + n++; np=np->next; } @@ -174,17 +231,66 @@ } } -#if 0 -static void +#ifdef MB_USE_INTERRUPTS +static void __pmac media_bay_intr(int irq, void *devid, struct pt_regs *regs) { - int id = MB_CONTENTS(); - - if (id == MB_NO) - set_media_bay(id); } #endif +static void __pmac +set_mb_power(int which, int onoff) +{ + volatile struct media_bay_info* mb = &media_bays[which]; + + if (onoff) { + feature_set(mb->dev_node, FEATURE_Mediabay_power); + udelay(10); + feature_set(mb->dev_node, FEATURE_Mediabay_reset); + udelay(10); + mb->state = mb_powering_up; + MBDBG("mediabay%d: powering up\n", which); + } else { + feature_clear(mb->dev_node, FEATURE_Mediabay_floppy_enable); + feature_clear(mb->dev_node, FEATURE_Mediabay_IDE_enable); + feature_clear(mb->dev_node, FEATURE_Mediabay_PCI_enable); + feature_clear(mb->dev_node, FEATURE_SWIM3_enable); + feature_clear(mb->dev_node, FEATURE_Mediabay_power); + mb->state = mb_powering_down; + MBDBG("mediabay%d: powering down\n", which); + } + mb->timer = MS_TO_HZ(MB_POWER_DELAY); +} + +static void __pmac +set_media_bay(int which, int id) +{ + volatile struct media_bay_info* bay; + + bay = &media_bays[which]; + + switch (id) { + case MB_CD: + feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable); + udelay(10); + feature_set(bay->dev_node, FEATURE_Mediabay_IDE_reset); + printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which); + break; + case MB_FD: + case MB_FD1: + feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable); + feature_set(bay->dev_node, FEATURE_SWIM3_enable); + printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which); + break; + case MB_NO: + break; + default: + printk(KERN_INFO "media bay %d contains an unknown device (%d)\n", + which, id); + break; + } +} + int __pmac check_media_bay(struct device_node *which_bay, int what) { @@ -194,7 +300,7 @@ for (i=0; istate != mb_powering_down) + poll_media_bay(i); + + /* If timer expired or polling IDE busy, run state machine */ + if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0)) + return; + + switch(bay->state) { + case mb_powering_up: + set_media_bay(i, bay->last_value); + bay->timer = MS_TO_HZ(MB_RESET_DELAY); + bay->state = mb_enabling_bay; + MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id); + break; + case mb_enabling_bay: + feature_clear(bay->dev_node, FEATURE_Mediabay_reset); + bay->timer = MS_TO_HZ(MB_SETUP_DELAY); + bay->state = mb_resetting; + MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id); + break; + + case mb_resetting: + if (bay->content_id != MB_CD) { + MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id); + bay->state = mb_up; + break; + } +#ifdef CONFIG_BLK_DEV_IDE + MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id); + feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_reset); + bay->timer = MS_TO_HZ(MB_IDE_WAIT); + bay->state = mb_ide_resetting; +#else + printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i); + set_mb_power(i, 0); +#endif // #ifdef CONFIG_BLK_DEV_IDE + break; + +#ifdef CONFIG_BLK_DEV_IDE + case mb_ide_resetting: + bay->timer = MS_TO_HZ(MB_IDE_TIMEOUT); + bay->state = mb_ide_waiting; + MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id); + break; + + case mb_ide_waiting: + if (bay->cd_base == 0) { + bay->timer = 0; + bay->state = mb_up; + MBDBG("mediabay%d: up before IDE init\n", i); + break; + } else if (MB_IDE_READY(i)) { + bay->timer = 0; + bay->state = mb_up; + if (bay->cd_index < 0) + bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq); + if (bay->cd_index == -1) { + /* We eventually do a retry */ + bay->cd_retry++; + printk("IDE register error\n"); + set_mb_power(i, 0); + } else { + printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index); + MBDBG("mediabay %d IDE ready\n", i); + } + break; + } + if (bay->timer == 0) { + printk("\nIDE Timeout in bay %d !\n", i); + MBDBG("mediabay%d: nIDE Timeout !\n", i); + set_mb_power(i, 0); + } + break; +#endif // #ifdef CONFIG_BLK_DEV_IDE + + case mb_powering_down: + bay->state = mb_empty; +#ifdef CONFIG_BLK_DEV_IDE + if (bay->cd_index >= 0) { + printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, + bay->cd_index); + ide_unregister(bay->cd_index); + bay->cd_index = -1; + } + if (bay->cd_retry) { + if (bay->cd_retry > MAX_CD_RETRIES) { + /* Should add an error sound (sort of beep in dmasound) */ + printk("\nmedia-bay %d, IDE device badly inserted or unrecognised\n", i); + } else { + /* Force a new power down/up sequence */ + bay->content_id = MB_NO; + } + } +#endif + MBDBG("mediabay%d: end of power down\n", i); + break; + } +} + /* * This procedure runs as a kernel thread to poll the media bay * once each tick and register and unregister the IDE interface @@ -252,123 +476,57 @@ int __pmac media_bay_task(void *x) { - volatile struct media_bay_info* bay; int i = 0; strcpy(current->comm, "media-bay"); - for (;;) - { - bay = &media_bays[i]; - poll_media_bay(i); - if (bay->content_id != bay->previous_id) { - bay->reset_timer = (bay->content_id != MB_NO) ? - MB_RESET_COUNT: 0; - bay->ready = 0; -#ifdef CONFIG_BLK_DEV_IDE - bay->cd_timer = 0; - if (bay->content_id != MB_CD && bay->cd_index >= 0) { - printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); - ide_unregister(bay->cd_index); - bay->cd_index = -1; - } -#endif - } else if (bay->reset_timer) { - if (--bay->reset_timer == 0) { - feature_clear(bay->dev_node, FEATURE_Mediabay_reset); - bay->ready = 1; -#ifdef CONFIG_BLK_DEV_IDE - bay->cd_timer = 0; - if (bay->content_id == MB_CD && bay->cd_base != 0) - bay->cd_timer = MB_IDE_WAIT; -#endif - } -#ifdef CONFIG_BLK_DEV_IDE - } else if (bay->cd_timer && (--bay->cd_timer == 0 || MB_IDE_READY(i)) - && bay->cd_index < 0) { - bay->cd_timer = 0; - printk(KERN_DEBUG "Registering IDE, base:0x%08lx, irq:%d\n", bay->cd_base, bay->cd_irq); - printk("\n"); - bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq); - if (bay->cd_index == -1) - printk("\nCD-ROM badly inserted. Remove it and try again !\n"); - else - printk(KERN_DEBUG "media-bay %d is ide %d\n", i, bay->cd_index); +#ifdef MB_IGNORE_SIGNALS + sigfillset(¤t->blocked); #endif - } - bay->previous_id = bay->content_id; + for (;;) { + media_bay_step(i); + + if (++i >= media_bay_count) { + i = 0; current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); if (signal_pending(current)) return 0; - i = (i+1)%media_bay_count; + } } } void __pmac poll_media_bay(int which) { + volatile struct media_bay_info* bay = &media_bays[which]; int id = MB_CONTENTS(which); - if (id == media_bays[which].last_value) { - if (id != media_bays[which].content_id - && ++media_bays[which].value_count >= MB_STABLE_COUNT) { + if (id == bay->last_value) { + if (id != bay->content_id + && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) { /* If the device type changes without going thru "MB_NO", we force a pass by "MB_NO" to make sure things are properly reset */ - if ((id != MB_NO) && (media_bays[which].content_id != MB_NO)) { - set_media_bay(which, MB_NO); - udelay(500); + if ((id != MB_NO) && (bay->content_id != MB_NO)) { + id = MB_NO; + MBDBG("mediabay%d: forcing MB_NO\n", which); + } + MBDBG("mediabay%d: switching to %d\n", which, id); + set_mb_power(which, id != MB_NO); + bay->content_id = id; + if (id == MB_NO) { +#ifdef CONFIG_BLK_DEV_IDE + bay->cd_retry = 0; +#endif + printk(KERN_INFO "media bay %d is empty\n", which); } - set_media_bay(which, id); } } else { - media_bays[which].last_value = id; - media_bays[which].value_count = 0; + bay->last_value = id; + bay->value_count = 0; } } -static void __pmac -set_media_bay(int which, int id) -{ - volatile struct media_bay_info* bay; - - bay = &media_bays[which]; - - bay->content_id = id; - bay->last_value = id; - - switch (id) { - case MB_CD: - feature_set(bay->dev_node, FEATURE_Mediabay_enable); - feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable); - udelay(500); - feature_set(bay->dev_node, FEATURE_CD_power); - printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which); - break; - case MB_FD: - feature_set(bay->dev_node, FEATURE_Mediabay_enable); - feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable); - feature_set(bay->dev_node, FEATURE_SWIM3_enable); - printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which); - break; - case MB_NO: - feature_clear(bay->dev_node, FEATURE_CD_power); - feature_clear(bay->dev_node, FEATURE_Mediabay_enable); - feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); - feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable); - feature_clear(bay->dev_node, FEATURE_SWIM3_enable); - feature_set(bay->dev_node, FEATURE_Mediabay_reset); - printk(KERN_INFO "media bay %d is empty\n", which); - break; - default: - feature_set(bay->dev_node, FEATURE_Mediabay_enable); - printk(KERN_INFO "media bay %d contains an unknown device (%d)\n", - which, id); - break; - } - - udelay(500); -} #ifdef CONFIG_PMAC_PBOOK /* @@ -388,42 +546,34 @@ case PBOOK_SLEEP_NOW: for (i=0; idev_node, FEATURE_Mediabay_enable); - feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable); - feature_clear(bay->dev_node, FEATURE_SWIM3_enable); - feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable); - feature_set(bay->dev_node, FEATURE_Mediabay_reset); - feature_clear(bay->dev_node, FEATURE_CD_power); - out_8(&media_bays[i].addr->contents, 0x70); + set_mb_power(i, 0); + mdelay(10); + out_8(&bay->addr->contents, 0x70); } break; case PBOOK_WAKE: for (i=0; idev_node, FEATURE_Mediabay_enable); - /* I suppose this is enough delay to stabilize MB_CONTENT ... */ - mdelay(10); - /* We re-enable the bay using it's previous content only if - it did not change */ - if (MB_CONTENTS(i) == bay->content_id) { - set_media_bay(i, bay->content_id); - if (bay->content_id != MB_NO) { - mdelay(400); - /* Clear the bay reset */ - feature_clear(bay->dev_node, FEATURE_Mediabay_reset); - /* This small delay makes sure the device has time - to assert the BUSY bit (used by IDE sleep) */ - udelay(100); - /* We reset the state machine timers in case we were in the - middle of a wait loop */ - if (bay->reset_timer) - bay->reset_timer = MB_RESET_COUNT; -#ifdef CONFIG_BLK_DEV_IDE - if (bay->cd_timer) - bay->cd_timer = MB_IDE_WAIT; -#endif - } - } + /* We re-enable the bay using it's previous content + only if it did not change. Note those bozo timings, they seem + to help the 3400 get it right + */ + mdelay(MB_STABLE_DELAY); + out_8(&bay->addr->contents, 0x70); + mdelay(MB_STABLE_DELAY); + if (MB_CONTENTS(i) != bay->content_id) + continue; + set_mb_power(i, 1); + mdelay(MB_POWER_DELAY); + media_bays[i].last_value = bay->content_id; + media_bays[i].value_count = MS_TO_HZ(MB_STABLE_DELAY); + media_bays[i].timer = 0; + media_bays[i].cd_retry = 0; + do { + mdelay(1000/HZ); + media_bay_step(i); + } while((media_bays[i].state != mb_empty) && + (media_bays[i].state != mb_up)); } break; } diff -u --recursive --new-file v2.3.42/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c --- v2.3.42/linux/drivers/macintosh/nvram.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/macintosh/nvram.c Wed Feb 9 11:42:35 2000 @@ -83,17 +83,11 @@ } struct file_operations nvram_fops = { - nvram_llseek, - read_nvram, - write_nvram, - NULL, /* nvram_readdir */ - NULL, /* nvram_select */ - NULL, /* nvram_ioctl */ - NULL, /* nvram_mmap */ - nvram_open, - NULL, /* flush */ - nvram_release, - NULL /* fsync */ + llseek: nvram_llseek, + read: read_nvram, + write: write_nvram, + open: nvram_open, + release: nvram_release, }; static struct miscdevice nvram_dev = { diff -u --recursive --new-file v2.3.42/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c --- v2.3.42/linux/drivers/macintosh/via-pmu.c Thu Jan 6 12:57:47 2000 +++ linux/drivers/macintosh/via-pmu.c Wed Feb 9 19:43:53 2000 @@ -9,6 +9,12 @@ * and the RTC (real time clock) chip. * * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. + * + * todo: - Check this driver for smp safety (new Core99 motherboards). + * - Cleanup synchro between VIA interrupt and GPIO-based PMU + * interrupt. + * + * */ #include #include @@ -91,13 +97,16 @@ static unsigned char *reply_ptr; static int data_index; static int data_len; -static int adb_int_pending; +static volatile int adb_int_pending; static int pmu_adb_flags; static int adb_dev_map = 0; static struct adb_request bright_req_1, bright_req_2, bright_req_3; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; +static int pmu_has_adb, pmu_has_backlight; +static unsigned char *gpio_reg = NULL; +static int gpio_irq; int asleep; struct notifier_block *sleep_notifier_list; @@ -118,6 +127,7 @@ static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); static void set_volume(int level); +static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); #ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); #endif @@ -191,6 +201,7 @@ "PowerBook 2400/3400/3500(G3)", "PowerBook G3 Series", "1999 PowerBook G3", + "Core99 (iBook/iMac/G4)" }; int __openfirmware @@ -203,9 +214,6 @@ return 0; if (vias->next != 0) printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); - - feature_set(vias, FEATURE_VIA_enable); - #if 0 { int i; @@ -218,13 +226,16 @@ printk("\n"); } #endif - if (vias->n_addrs != 1 || vias->n_intrs != 1) { + if (vias->n_addrs < 1 || vias->n_intrs < 1) { printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n", vias->n_addrs, vias->n_intrs); if (vias->n_addrs < 1 || vias->n_intrs < 1) return 0; } + pmu_has_adb = 1; + pmu_has_backlight = 1; + if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) || device_is_compatible(vias->parent, "ohare"))) pmu_kind = PMU_OHARE_BASED; @@ -232,12 +243,17 @@ pmu_kind = PMU_PADDINGTON_BASED; else if (device_is_compatible(vias->parent, "heathrow")) pmu_kind = PMU_HEATHROW_BASED; - else + else if (device_is_compatible(vias->parent, "Keylargo")) { + pmu_kind = PMU_KEYLARGO_BASED; + pmu_has_adb = (find_type_devices("adb") != NULL); + pmu_has_backlight = (find_type_devices("backlight") != NULL); + } else pmu_kind = PMU_UNKNOWN; via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ + out_8(&via[IFR], 0x7f); /* clear IFR */ pmu_state = idle; @@ -289,6 +305,23 @@ return; } + if (pmu_kind == PMU_KEYLARGO_BASED) { + struct device_node *gpio, *gpiop; + + gpiop = find_devices("gpio"); + if (gpiop && gpiop->n_addrs) { + gpio_reg = ioremap(gpiop->addrs->address, 0x10); + gpio = find_devices("extint-gpio1"); + if (gpio && gpio->parent == gpiop && gpio->n_intrs) { + gpio_irq = gpio->intrs[0].line; + if (request_irq(gpio_irq, gpio1_interrupt, 0, + "GPIO1/ADB", (void *)0)) + printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", + gpio->intrs[0].line); + } + } + } + /* Enable interrupts */ out_8(&via[IER], IER_SET | SR_INT | CB1_INT); @@ -395,6 +428,8 @@ } break; case ADB_PACKET: + if (!pmu_has_adb) + return -ENXIO; for (i = req->nbytes - 1; i > 1; --i) req->data[i+2] = req->data[i]; req->data[3] = req->nbytes - 2; @@ -425,7 +460,7 @@ { struct adb_request req; - if ((vias == NULL) || (!pmu_fully_inited)) + if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb) return -ENXIO; if (devs) { @@ -447,10 +482,9 @@ pmu_adb_reset_bus(void) { struct adb_request req; - long timeout; int save_autopoll = adb_dev_map; - if ((vias == NULL) || (!pmu_fully_inited)) + if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb) return -ENXIO; /* anyone got a better idea?? */ @@ -460,27 +494,17 @@ req.done = NULL; req.data[0] = PMU_ADB_CMD; req.data[1] = 0; - req.data[2] = 3; /* ADB_BUSRESET ??? */ + req.data[2] = ADB_BUSRESET; /* 3 ??? */ req.data[3] = 0; req.data[4] = 0; req.reply_len = 0; req.reply_expected = 1; - if (pmu_queue_request(&req) != 0) - { + if (pmu_queue_request(&req) != 0) { printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n"); return -EIO; } while (!req.complete) pmu_poll(); - timeout = 100000; - while (!req.complete) { - if (--timeout < 0) { - printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n"); - return -EIO; - } - udelay(10); - pmu_poll(); - } if (save_autopoll != 0) pmu_adb_autopoll(save_autopoll); @@ -558,6 +582,8 @@ return 0; } +/* New PMU seems to be very sensitive to those timings, so we make sure + * PCI is flushed immediately */ static void __openfirmware send_byte(int x) { @@ -566,6 +592,7 @@ out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT); out_8(&v[SR], x); out_8(&v[B], in_8(&v[B]) & ~TREQ); /* assert TREQ */ + (void)in_8(&v[B]); } static void __openfirmware @@ -575,10 +602,11 @@ out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT); in_8(&v[SR]); /* resets SR */ - out_8(&v[B], in_8(&v[B]) & ~0x10); + out_8(&v[B], in_8(&v[B]) & ~TREQ); + (void)in_8(&v[B]); } -static int disable_poll; +static volatile int disable_poll; static void __openfirmware pmu_start() @@ -616,7 +644,8 @@ return; save_flags(flags); cli(); - if (via[IFR] & (SR_INT | CB1_INT)) + if ((via[IFR] & (SR_INT | CB1_INT)) || + (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)) via_pmu_interrupt(0, 0, 0); restore_flags(flags); } @@ -626,7 +655,12 @@ { int intr; int nloop = 0; + unsigned long flags; + /* Currently, we use brute-force cli() for syncing with GPIO + * interrupt. I'll make this smarter later, along with some + * spinlocks for SMP */ + save_flags(flags);cli(); ++disable_poll; while ((intr = in_8(&via[IFR])) != 0) { if (++nloop > 1000) { @@ -645,6 +679,9 @@ out_8(&via[IFR], intr); } } + if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0) + adb_int_pending = 1; + if (pmu_state == idle) { if (adb_int_pending) { pmu_state = intack; @@ -655,6 +692,13 @@ } } --disable_poll; + restore_flags(flags); +} + +static void __openfirmware +gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + via_pmu_interrupt(0, 0, 0); } static void __openfirmware @@ -668,9 +712,17 @@ out_8(&via[IFR], SR_INT); return; } - if (via[B] & TACK) + /* This one seems to appear with PMU99. According to OF methods, + * the protocol didn't change... + */ + if (via[B] & TACK) { + while ((in_8(&via[B]) & TACK) != 0) + ; +#if 0 printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n", via[B]); +#endif + } /* reset TREQ and wait for TACK to go high */ out_8(&via[B], in_8(&via[B]) | TREQ); @@ -832,7 +884,7 @@ { struct adb_request req; - if (vias == NULL) + if ((vias == NULL) || !pmu_has_backlight) return; /* first call: get current backlight value */ @@ -853,6 +905,7 @@ printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level); break; case PMU_PADDINGTON_BASED: + case PMU_KEYLARGO_BASED: /* the G3 PB 1999 has a backlight node and chrp-structured nvram */ /* XXX should read macos's "blkt" property in nvram @@ -883,7 +936,7 @@ { int bright; - if (vias == NULL) + if ((vias == NULL) || !pmu_has_backlight) return ; backlight_level = level; @@ -963,6 +1016,12 @@ ; } +int +pmu_present(void) +{ + return via != 0; +} + #ifdef CONFIG_PMAC_PBOOK static LIST_HEAD(sleep_notifiers); @@ -995,7 +1054,7 @@ /* Sleep is broadcast last-to-first */ static int -broadcast_sleep(int when, int can_cancel) +broadcast_sleep(int when, int fallback) { int ret = PBOOK_SLEEP_OK; struct list_head *list; @@ -1005,8 +1064,13 @@ list = list->prev) { current = list_entry(list, struct pmu_sleep_notifier, list); ret = current->notifier_call(current, when); - if (can_cancel && (ret != PBOOK_SLEEP_OK)) + if (ret != PBOOK_SLEEP_OK) { + for (; list != &sleep_notifiers; list = list->next) { + current = list_entry(list, struct pmu_sleep_notifier, list); + current->notifier_call(current, fallback); + } return ret; + } } return ret; } @@ -1101,6 +1165,24 @@ } } +#if 0 +/* N.B. This doesn't work on the 3400 */ +void pmu_blink(int n) +{ + struct adb_request req; + + for (; n > 0; --n) { + pmu_request(&req, NULL, 4, 0xee, 4, 0, 1); + while (!req.complete) pmu_poll(); + udelay(50000); + pmu_request(&req, NULL, 4, 0xee, 4, 0, 0); + while (!req.complete) pmu_poll(); + udelay(50000); + } + udelay(50000); +} +#endif + /* * Put the powerbook to sleep. */ @@ -1127,19 +1209,27 @@ macio_base = (unsigned long) ioremap(macio->addrs[0].address, 0x40); + /* Notify device drivers */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep rejected\n"); + return -EBUSY; + } + /* Sync the disks. */ /* XXX It would be nice to have some way to ensure that - * nobody is dirtying any new buffers while we wait. */ + * nobody is dirtying any new buffers while we wait. + * BenH: Moved to _after_ sleep request and changed video + * drivers to vmalloc() during sleep request. This way, all + * vmalloc's are done before actual sleep of block drivers */ fsync_dev(0); - /* Notify device drivers */ - ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1); + /* Sleep can fail now. May not be very robust but useful for debugging */ + ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { - broadcast_sleep(PBOOK_SLEEP_REJECT, 0); - printk("pmu: sleep rejected\n"); + printk("pmu: sleep failed\n"); return -EBUSY; } - broadcast_sleep(PBOOK_SLEEP_NOW, 0); /* Give the disks a little time to actually finish writing */ for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) @@ -1191,6 +1281,10 @@ pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); + /* Make sure the PMU is idle */ + while (pmu_state != idle) + pmu_poll(); + sti(); #if 0 /* According to someone from Apple, this should not be needed, @@ -1202,8 +1296,8 @@ /* Restore L2 cache */ if (save_l2cr) - _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */ - + _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */ + /* reenable interrupts */ sleep_restore_intrs(); @@ -1223,19 +1317,27 @@ unsigned long p, wait; struct adb_request sleep_req; + /* Notify device drivers */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep rejected\n"); + return -EBUSY; + } + /* Sync the disks. */ /* XXX It would be nice to have some way to ensure that - * nobody is dirtying any new buffers while we wait. */ + * nobody is dirtying any new buffers while we wait. + * BenH: Moved to _after_ sleep request and changed video + * drivers to vmalloc() during sleep request. This way, all + * vmalloc's are done before actual sleep of block drivers */ fsync_dev(0); - /* Notify device drivers */ - ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1); + /* Sleep can fail now. May not be very robust but useful for debugging */ + ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); if (ret != PBOOK_SLEEP_OK) { - broadcast_sleep(PBOOK_SLEEP_REJECT, 0); - printk("pmu: sleep rejected\n"); + printk("pmu: sleep failed\n"); return -EBUSY; } - broadcast_sleep(PBOOK_SLEEP_NOW, 0); /* Give the disks a little time to actually finish writing */ for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) @@ -1462,33 +1564,35 @@ error = powerbook_sleep_G3(); break; default: - error = ENOSYS; + error = -ENOSYS; } return error; case PMU_IOC_GET_BACKLIGHT: + if (!pmu_has_backlight) + return -ENOSYS; return put_user(backlight_level, (__u32 *)arg); case PMU_IOC_SET_BACKLIGHT: + if (!pmu_has_backlight) + return -ENOSYS; error = get_user(value, (__u32 *)arg); if (!error) pmu_set_brightness(value); return error; case PMU_IOC_GET_MODEL: return put_user(pmu_kind, (__u32 *)arg); + case PMU_IOC_HAS_ADB: + return put_user(pmu_has_adb, (__u32 *)arg); } return -EINVAL; } static struct file_operations pmu_device_fops = { - NULL, /* no seek */ - pmu_read, - pmu_write, - NULL, /* no readdir */ - pmu_fpoll, - pmu_ioctl, - NULL, /* no mmap */ - pmu_open, - NULL, /* flush */ - pmu_release, + read: pmu_read, + write: pmu_write, + poll: pmu_fpoll, + ioctl: pmu_ioctl, + open: pmu_open, + release: pmu_release, }; static struct miscdevice pmu_device = { @@ -1502,3 +1606,70 @@ } #endif /* CONFIG_PMAC_PBOOK */ +#if 0 +static inline void polled_handshake(volatile unsigned char *via) +{ + via[B] &= ~TREQ; eieio(); + while ((via[B] & TACK) != 0) + ; + via[B] |= TREQ; eieio(); + while ((via[B] & TACK) == 0) + ; +} + +static inline void polled_send_byte(volatile unsigned char *via, int x) +{ + via[ACR] |= SR_OUT | SR_EXT; eieio(); + via[SR] = x; eieio(); + polled_handshake(via); +} + +static inline int polled_recv_byte(volatile unsigned char *via) +{ + int x; + + via[ACR] = (via[ACR] & ~SR_OUT) | SR_EXT; eieio(); + x = via[SR]; eieio(); + polled_handshake(via); + x = via[SR]; eieio(); + return x; +} + +int +pmu_polled_request(struct adb_request *req) +{ + unsigned long flags; + int i, l, c; + volatile unsigned char *v = via; + + req->complete = 1; + c = req->data[0]; + l = pmu_data_len[c][0]; + if (l >= 0 && req->nbytes != l + 1) + return -EINVAL; + + save_flags(flags); cli(); + while (pmu_state != idle) + pmu_poll(); + + polled_send_byte(v, c); + if (l < 0) { + l = req->nbytes - 1; + polled_send_byte(v, l); + } + for (i = 1; i <= l; ++i) + polled_send_byte(v, req->data[i]); + + l = pmu_data_len[c][1]; + if (l < 0) + l = polled_recv_byte(v); + for (i = 0; i < l; ++i) + req->reply[i + req->reply_len] = polled_recv_byte(v); + + if (req->done) + (*req->done)(req); + + restore_flags(flags); + return 0; +} +#endif /* 0 */ diff -u --recursive --new-file v2.3.42/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v2.3.42/linux/drivers/net/3c501.c Fri Sep 10 23:57:29 1999 +++ linux/drivers/net/3c501.c Thu Feb 10 12:34:24 2000 @@ -29,54 +29,64 @@ with a TX-TX optimisation to see if we can touch 180-200K/second as seems theoretically maximum. 19950402 Alan Cox + + Cleaned up for 2.3.x because we broke SMP now. + 20000208 Alan Cox + +*/ - Some notes on this thing if you have to hack it. [Alan] - - 1] Some documentation is available from 3Com. Due to the boards age - standard responses when you ask for this will range from 'be serious' - to 'give it to a museum'. The documentation is incomplete and mostly - of historical interest anyway. - - 2] The basic system is a single buffer which can be used to receive or - transmit a packet. A third command mode exists when you are setting - things up. - - 3] If it's transmitting it's not receiving and vice versa. In fact the - time to get the board back into useful state after an operation is - quite large. - - 4] The driver works by keeping the board in receive mode waiting for a - packet to arrive. When one arrives it is copied out of the buffer - and delivered to the kernel. The card is reloaded and off we go. - - 5] When transmitting dev->tbusy is set and the card is reset (from - receive mode) [possibly losing a packet just received] to command - mode. A packet is loaded and transmit mode triggered. The interrupt - handler runs different code for transmit interrupts and can handle - returning to receive mode or retransmissions (yes you have to help - out with those too). - - Problems: - There are a wide variety of undocumented error returns from the card - and you basically have to kick the board and pray if they turn up. Most - only occur under extreme load or if you do something the board doesn't - like (eg touching a register at the wrong time). - - The driver is less efficient than it could be. It switches through - receive mode even if more transmits are queued. If this worries you buy - a real Ethernet card. - - The combination of slow receive restart and no real multicast - filter makes the board unusable with a kernel compiled for IP - multicasting in a real multicast environment. That's down to the board, - but even with no multicast programs running a multicast IP kernel is - in group 224.0.0.1 and you will therefore be listening to all multicasts. - One nv conference running over that Ethernet and you can give up. -*/ +/** + * DOC: 3c501 Card Notes + * + * Some notes on this thing if you have to hack it. [Alan] + * + * Some documentation is available from 3Com. Due to the boards age + * standard responses when you ask for this will range from 'be serious' + * to 'give it to a museum'. The documentation is incomplete and mostly + * of historical interest anyway. + * + * The basic system is a single buffer which can be used to receive or + * transmit a packet. A third command mode exists when you are setting + * things up. + * + * If it's transmitting it's not receiving and vice versa. In fact the + * time to get the board back into useful state after an operation is + * quite large. + * + * The driver works by keeping the board in receive mode waiting for a + * packet to arrive. When one arrives it is copied out of the buffer + * and delivered to the kernel. The card is reloaded and off we go. + * + * When transmitting lp->txing is set and the card is reset (from + * receive mode) [possibly losing a packet just received] to command + * mode. A packet is loaded and transmit mode triggered. The interrupt + * handler runs different code for transmit interrupts and can handle + * returning to receive mode or retransmissions (yes you have to help + * out with those too). + * + * DOC: Problems + * + * There are a wide variety of undocumented error returns from the card + * and you basically have to kick the board and pray if they turn up. Most + * only occur under extreme load or if you do something the board doesn't + * like (eg touching a register at the wrong time). + * + * The driver is less efficient than it could be. It switches through + * receive mode even if more transmits are queued. If this worries you buy + * a real Ethernet card. + * + * The combination of slow receive restart and no real multicast + * filter makes the board unusable with a kernel compiled for IP + * multicasting in a real multicast environment. That's down to the board, + * but even with no multicast programs running a multicast IP kernel is + * in group 224.0.0.1 and you will therefore be listening to all multicasts. + * One nv conference running over that Ethernet and you can give up. + * + */ static const char *version = - "3c501.c: 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov).\n"; + "3c501.c: 2000/02/08 Alan Cox (alan@redhat.com).\n"; /* * Braindamage remaining: @@ -119,6 +129,7 @@ int el1_probe(struct net_device *dev); static int el1_probe1(struct net_device *dev, int ioaddr); static int el_open(struct net_device *dev); +static void el_timeout(struct net_device *dev); static int el_start_xmit(struct sk_buff *skb, struct net_device *dev); static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void el_receive(struct net_device *dev); @@ -144,6 +155,7 @@ int tx_pkt_start; /* The length of the current Tx packet. */ int collisions; /* Tx collisions this packet */ int loading; /* Spot buffer load collisions */ + int txing; /* True if card is in TX mode */ spinlock_t lock; /* Serializing lock */ }; @@ -210,6 +222,19 @@ struct netdev_entry el1_drv = {"3c501", el1_probe1, EL1_IO_EXTENT, netcard_portlist}; #else +/** + * el1_probe: + * @dev: The device structure passed in to probe. + * + * This can be called from two places. The network layer will probe using + * a device structure passed in with the probe information completed. For a + * modular driver we use #init_module to fill in our own structure and probe + * for it. + * + * Returns 0 on success. ENXIO if asked not to probe and ENODEV if asked to + * probe and failing to find anything. + */ + int __init el1_probe(struct net_device *dev) { int i; @@ -233,8 +258,17 @@ } #endif -/* - * The actual probe. +/** + * el1_probe: + * @dev: The device structure to use + * @ioaddr: An I/O address to probe at. + * + * The actual probe. This is iterated over by #el1_probe in order to + * check all the applicable device locations. + * + * Returns 0 for a success, in which case the device is activated, + * EAGAIN if the IRQ is in use by another driver, and ENODEV if the + * board cannot be found. */ static int __init el1_probe1(struct net_device *dev, int ioaddr) @@ -310,11 +344,11 @@ if (autoirq) dev->irq = autoirq; - printk("%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr, + printk(KERN_INFO "%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq); #ifdef CONFIG_IP_MULTICAST - printk("WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); + printk(KERN_WARNING "WARNING: Use of the 3c501 in a multicast kernel is NOT recommended.\n"); #endif if (el_debug) @@ -338,6 +372,8 @@ dev->open = &el_open; dev->hard_start_xmit = &el_start_xmit; + dev->tx_timeout = &el_timeout; + dev->watchdog_timeo = HZ; dev->stop = &el1_close; dev->get_stats = &el1_get_stats; dev->set_multicast_list = &set_multicast_list; @@ -351,13 +387,24 @@ return 0; } -/* - * Open/initialize the board. +/** + * el1_open: + * @dev: device that is being opened + * + * When an ifconfig is issued which changes the device flags to include + * IFF_UP this function is called. It is only called when the change + * occurs, not when the interface remains up. #el1_close will be called + * when it goes down. + * + * Returns 0 for a successful open, or -EAGAIN if someone has run off + * with our interrupt line. */ static int el_open(struct net_device *dev) { int ioaddr = dev->base_addr; + struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; if (el_debug > 2) printk("%s: Doing el_open()...", dev->name); @@ -365,47 +412,75 @@ if (request_irq(dev->irq, &el_interrupt, 0, "3c501", dev)) return -EAGAIN; + spin_lock_irqsave(&lp->lock, flags); el_reset(dev); + spin_unlock_irqrestore(&lp->lock, flags); - dev->start = 1; - + lp->txing = 0; /* Board in RX mode */ outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */ + netif_start_queue(dev); MOD_INC_USE_COUNT; return 0; } -static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) +/** + * el_timeout: + * @dev: The 3c501 card that has timed out + * + * Attempt to restart the board. This is basically a mixture of extreme + * violence and prayer + * + */ + +static void el_timeout(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; - unsigned long flags; + + if (el_debug) + printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", + dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); + lp->stats.tx_errors++; + outb(TX_NORM, TX_CMD); + outb(RX_NORM, RX_CMD); + outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */ + outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */ + lp->txing = 0; /* Ripped back in to RX */ + netif_wake_queue(dev); +} - if(dev->interrupt) /* May be unloading, don't stamp on */ - return 1; /* the packet buffer this time */ + +/** + * el_start_xmit: + * @skb: The packet that is queued to be sent + * @dev: The 3c501 card we want to throw it down + * + * Attempt to send a packet to a 3c501 card. There are some interesting + * catches here because the 3c501 is an extremely old and therefore + * stupid piece of technology. + * + * If we are handling an interrupt on the other CPU we cannot load a packet + * as we may still be attempting to retrieve the last RX packet buffer. + * + * When a transmit times out we dump the card into control mode and just + * start again. It happens enough that it isnt worth logging. + * + * We avoid holding the spin locks when doing the packet load to the board. + * The device is very slow, and its DMA mode is even slower. If we held the + * lock while loading 1500 bytes onto the controller we would drop a lot of + * serial port characters. This requires we do extra locking, but we have + * no real choice. + */ - if (dev->tbusy) - { - if (jiffies - dev->trans_start < 20) - { - if (el_debug > 2) - printk(" transmitter busy, deferred.\n"); - return 1; - } - if (el_debug) - printk ("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", - dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); - lp->stats.tx_errors++; - outb(TX_NORM, TX_CMD); - outb(RX_NORM, RX_CMD); - outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */ - outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */ - dev->tbusy = 0; - dev->trans_start = jiffies; - } +static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; /* - * Avoid incoming interrupts between us flipping tbusy and flipping - * mode as the driver assumes tbusy is a faithful indicator of card + * Avoid incoming interrupts between us flipping txing and flipping + * mode as the driver assumes txing is a faithful indicator of card * state */ @@ -415,17 +490,13 @@ * Avoid timer-based retransmission conflicts. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - { - spin_unlock_irqrestore(&lp->lock, flags); - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - } - else + netif_stop_queue(dev); + + do { int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); unsigned char *buf = skb->data; -load_it_again_sam: lp->tx_pkt_start = gp_start; lp->collisions = 0; @@ -440,7 +511,8 @@ inb_p(RX_STATUS); inb_p(TX_STATUS); - lp->loading=1; + lp->loading = 1; + lp->txing = 1; /* * Turn interrupts back on while we spend a pleasant afternoon @@ -453,29 +525,48 @@ outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */ outsb(DATAPORT,buf,skb->len); /* load buffer (usual thing each byte increments the pointer) */ outw(gp_start, GP_LOW); /* the board reuses the same register */ - - if(lp->loading==2) /* A receive upset our load, despite our best efforts */ + + if(lp->loading != 2) { - if(el_debug>2) - printk("%s: burped during tx load.\n", dev->name); - spin_lock_irqsave(&lp->lock, flags); - goto load_it_again_sam; /* Sigh... */ + outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */ + lp->loading=0; + dev->trans_start = jiffies; + if (el_debug > 2) + printk(" queued xmit.\n"); + dev_kfree_skb (skb); + return 0; } - outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */ - lp->loading=0; - dev->trans_start = jiffies; + /* A receive upset our load, despite our best efforts */ + if(el_debug>2) + printk("%s: burped during tx load.\n", dev->name); + spin_lock_irqsave(&lp->lock, flags); } + while(1); - if (el_debug > 2) - printk(" queued xmit.\n"); - dev_kfree_skb (skb); - return 0; } -/* - * The typical workload of the driver: - * Handle the ether interface interrupts. +/** + * el_interrupt: + * @irq: Interrupt number + * @dev_id: The 3c501 that burped + * @regs: Register data (surplus to our requirements) + * + * Handle the ether interface interrupts. The 3c501 needs a lot more + * hand holding than most cards. In paticular we get a transmit interrupt + * with a collision error because the board firmware isnt capable of rewinding + * its own transmit buffer pointers. It can however count to 16 for us. + * + * On the receive side the card is also very dumb. It has no buffering to + * speak of. We simply pull the packet out of its PIO buffer (which is slow) + * and queue it for the kernel. Then we reset the card for the next packet. + * + * We sometimes get suprise interrupts late both because the SMP IRQ delivery + * is message passing and because the card sometimes seems to deliver late. I + * think if it is part way through a receive and the mode is changed it carries + * on receiving and sends us an interrupt. We have to band aid all these cases + * to get a sensible 150kbytes/second performance. Even then you want a small + * TCP window. */ static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -485,12 +576,6 @@ int ioaddr; int axsr; /* Aux. status reg. */ - if (dev == NULL || dev->irq != irq) - { - printk (KERN_ERR "3c501 driver: irq %d for unknown device.\n", irq); - return; - } - ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; @@ -508,14 +593,12 @@ if (el_debug > 3) printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x", dev->name, axsr); - if (dev->interrupt) - printk(KERN_WARNING "%s: Reentering the interrupt driver!\n", dev->name); - dev->interrupt = 1; - if(lp->loading==1 && !dev->tbusy) + + if(lp->loading==1 && !lp->txing) printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n", dev->name); - if (dev->tbusy) + if (lp->txing) { /* @@ -533,7 +616,6 @@ printk(" txsr=%02x gp=%04x rp=%04x]\n", txsr, inw(GP_LOW),inw(RX_LOW)); } lp->loading=2; /* Force a reload */ - dev->interrupt = 0; spin_unlock(&lp->lock); return; } @@ -551,8 +633,8 @@ printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x" " gp=%03x rp=%03x.\n", dev->name, txsr, axsr, inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); - dev->tbusy = 0; - mark_bh(NET_BH); + lp->txing = 0; + netif_wake_queue(dev); } else if (txsr & TX_16COLLISIONS) { @@ -562,7 +644,9 @@ if (el_debug) printk("%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name); outb(AX_SYS, AX_CMD); + lp->txing = 0; lp->stats.tx_aborted_errors++; + netif_wake_queue(dev); } else if (txsr & TX_COLLISION) { @@ -580,7 +664,6 @@ outw(lp->tx_pkt_start, GP_LOW); outb(AX_XMIT, AX_CMD); lp->stats.collisions++; - dev->interrupt = 0; spin_unlock(&lp->lock); return; } @@ -597,8 +680,8 @@ * This is safe the interrupt is atomic WRT itself. */ - dev->tbusy = 0; - mark_bh(NET_BH); /* In case more to transmit */ + lp->txing = 0; + netif_wake_queue(dev); /* In case more to transmit */ } } else @@ -650,15 +733,19 @@ outw(0x00, RX_BUF_CLR); inb(RX_STATUS); /* Be certain that interrupts are cleared. */ inb(TX_STATUS); - dev->interrupt = 0; spin_unlock(&lp->lock); return; } -/* - * We have a good packet. Well, not really "good", just mostly not broken. - * We must check everything to see if it is good. +/** + * el_receive: + * @dev: Device to pull the packets from + * + * We have a good packet. Well, not really "good", just mostly not broken. + * We must check everything to see if it is good. In paticular we occasionally + * get wild packet sizes from the card. If the packet seems sane we PIO it + * off the card and queue it for the protocol layers. */ static void el_receive(struct net_device *dev) @@ -717,8 +804,18 @@ return; } +/** + * el_reset: Reset a 3c501 card + * @dev: The 3c501 card about to get zapped + * + * Even resetting a 3c501 isnt simple. When you activate reset it loses all + * its configuration. You must hold the lock when doing this. The function + * cannot take the lock itself as it is callable from the irq handler. + */ + static void el_reset(struct net_device *dev) { + struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; if (el_debug> 2) @@ -732,16 +829,24 @@ } outw(0, RX_BUF_CLR); /* Set rx packet area to 0. */ - cli(); /* Avoid glitch on writes to CMD regs */ outb(TX_NORM, TX_CMD); /* tx irq on done, collision */ outb(RX_NORM, RX_CMD); /* Set Rx commands. */ inb(RX_STATUS); /* Clear status. */ inb(TX_STATUS); - dev->interrupt = 0; - dev->tbusy = 0; - sti(); + lp->txing = 0; } +/** + * el1_close: + * @dev: 3c501 card to shut down + * + * Close a 3c501 card. The IFF_UP flag has been cleared by the user via + * the SIOCSIFFLAGS ioctl. We stop any further transmissions being queued, + * and then disable the interrupts. Finally we reset the chip. The effects + * of the rest will be cleaned up by #el1_open. Always returns 0 indicating + * a success. + */ + static int el1_close(struct net_device *dev) { int ioaddr = dev->base_addr; @@ -749,9 +854,8 @@ if (el_debug > 2) printk("%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr); - dev->tbusy = 1; - dev->start = 0; - + netif_stop_queue(dev); + /* * Free and disable the IRQ. */ @@ -763,15 +867,31 @@ return 0; } +/** + * el1_get_stats: + * @dev: The card to get the statistics for + * + * In smarter devices this function is needed to pull statistics off the + * board itself. The 3c501 has no hardware statistics. We maintain them all + * so they are by definition always up to date. + * + * Returns the statistics for the card from the card private data + */ + static struct net_device_stats *el1_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; return &lp->stats; } -/* - * Set or clear the multicast filter for this adaptor. - * best-effort filtering. +/** + * set_multicast_list: + * @dev: The device to adjust + * + * Set or clear the multicast filter for this adaptor to use the best-effort + * filtering supported. The 3c501 supports only three modes of filtering. + * It always receives broadcasts and packets for itself. You can choose to + * optionally receive all packets, or all multicast packets on top of this. */ static void set_multicast_list(struct net_device *dev) @@ -812,6 +932,18 @@ MODULE_PARM(io, "i"); MODULE_PARM(irq, "i"); +/** + * init_module: + * + * When the driver is loaded as a module this function is called. We fake up + * a device structure with the base I/O and interrupt set as if it was being + * called from Space.c. This minimises the extra code that would otherwise + * be required. + * + * Returns 0 for success or -EIO if a card is not found. Returning an error + * here also causes the module to be unloaded + */ + int init_module(void) { dev_3c501.irq=irq; @@ -821,6 +953,13 @@ return 0; } +/** + * cleanup_module: + * + * The module is being unloaded. We unhook our network device from the system + * and then free up the resources we took when the card was found. + */ + void cleanup_module(void) { /* diff -u --recursive --new-file v2.3.42/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v2.3.42/linux/drivers/net/3c503.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/3c503.c Thu Feb 10 12:34:24 2000 @@ -314,7 +314,6 @@ ei_status.saved_irq = dev->irq; - dev->start = 0; dev->open = &el2_open; dev->stop = &el2_close; diff -u --recursive --new-file v2.3.42/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.3.42/linux/drivers/net/3c507.c Thu Nov 11 20:11:39 1999 +++ linux/drivers/net/3c507.c Thu Feb 10 12:22:03 2000 @@ -40,7 +40,6 @@ info that the casual reader might think that it documents the i82586 :-<. */ -#include #include #include #include @@ -437,9 +436,7 @@ /* Initialize the 82586 memory and start it. */ init_82586_mem(dev); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); MOD_INC_USE_COUNT; @@ -453,7 +450,8 @@ unsigned long shmem = dev->mem_start; unsigned long flags; - if (dev->tbusy) +#if 0 /* LINK_STATE_XOFF is never set when we reach here */ + if (test_bit(LINK_STATE_XOFF, &dev->flags)) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ @@ -476,31 +474,30 @@ outb(0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */ lp->last_restart = lp->stats.tx_packets; } - dev->tbusy=0; + netif_start_queue(dev); dev->trans_start = jiffies; } +#endif - /* Block a timer-based transmit from overlapping. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); - else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; + spin_lock_irqsave(&lp->lock, flags); + lp->stats.tx_bytes+=length; /* Disable the 82586's input to the interrupt line. */ outb(0x80, ioaddr + MISC_CTRL); -#ifdef CONFIG_SMP - spin_lock_irqsave(&lp->lock, flags); - hardware_send_packet(dev, buf, length); - spin_unlock_irqrestore(&lp->lock, flags); -#else + hardware_send_packet(dev, buf, length); -#endif + dev->trans_start = jiffies; /* Enable the 82586 interrupt input. */ outb(0x84, ioaddr + MISC_CTRL); + + spin_unlock_irqrestore(&lp->lock, flags); + + netif_stop_queue(dev); } dev_kfree_skb (skb); @@ -524,8 +521,6 @@ printk ("net_interrupt(): irq %d for unknown device.\n", irq); return; } - dev->interrupt = 1; - ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; @@ -553,8 +548,7 @@ if (tx_status & 0x2000) { lp->stats.tx_packets++; lp->stats.collisions += tx_status & 0xf; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue(dev); } else { lp->stats.tx_errors++; if (tx_status & 0x0600) lp->stats.tx_carrier_errors++; @@ -580,7 +574,8 @@ /* Acknowledge the interrupt sources. */ ack_cmd = status & 0xf000; - if ((status & 0x0700) != 0x0200 && dev->start) { + if ((status & 0x0700) != 0x0200 && + (test_bit(LINK_STATE_START, &dev->state))) { if (net_debug) printk("%s: Command unit stopped, status %04x, restarting.\n", dev->name, status); @@ -590,7 +585,8 @@ ack_cmd |= CUC_RESUME; } - if ((status & 0x0070) != 0x0040 && dev->start) + if ((status & 0x0070) != 0x0040 && + (test_bit(LINK_STATE_START, &dev->state))) { static void init_rx_bufs(struct net_device *); /* The Rx unit is not ready, it must be hung. Restart the receiver by @@ -612,8 +608,6 @@ /* Enable the 82586's interrupt input. */ outb(0x84, ioaddr + MISC_CTRL); spin_unlock(&lp->lock); - - return; } static int el16_close(struct net_device *dev) @@ -621,8 +615,7 @@ int ioaddr = dev->base_addr; unsigned long shmem = dev->mem_start; - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); /* Flush the Tx and disable Rx. */ isa_writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD); @@ -795,7 +788,7 @@ } if (lp->tx_head != lp->tx_reap) - dev->tbusy = 0; + netif_start_queue(dev); } static void el16_rx(struct net_device *dev) diff -u --recursive --new-file v2.3.42/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.3.42/linux/drivers/net/3c509.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/3c509.c Thu Feb 10 12:31:07 2000 @@ -53,6 +53,7 @@ #include #include +#include #include #include #include @@ -149,6 +150,7 @@ static int el3_rx(struct net_device *dev); static int el3_close(struct net_device *dev); static void set_multicast_list(struct net_device *dev); +static void el3_tx_timeout (struct net_device *dev); #ifdef CONFIG_MCA struct el3_mca_adapters_struct { @@ -166,12 +168,34 @@ }; #endif +#ifdef CONFIG_ISAPNP +struct el3_isapnp_adapters_struct { + unsigned short vendor, function; + char *name; +}; +struct el3_isapnp_adapters_struct el3_isapnp_adapters[] = { + {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), "3Com Etherlink III (TP)"}, + {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091), "3Com Etherlink III"}, + {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094), "3Com Etherlink III (combo)"}, + {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095), "3Com Etherlink III (TPO)"}, + {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098), "3Com Etherlink III (TPC)"}, + {ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8), "3Com Etherlink III compatible"}, + {0, } +}; +u16 el3_isapnp_phys_addr[8][3] = { + {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, + {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0} +}; +#endif +static int nopnp = 0; + int el3_probe(struct net_device *dev) { short lrs_state = 0xff, i; int ioaddr, irq, if_port; u16 phys_addr[3]; static int current_tag = 0; + static int pnp_cards = 0; int mca_slot = -1; /* First check all slots of the EISA bus. The next slot address to @@ -265,9 +289,43 @@ return -ENODEV; } #endif - /* Reset the ISA PnP mechanism on 3c509b. */ - outb(0x02, 0x279); /* Select PnP config control register. */ - outb(0x02, 0xA79); /* Return to WaitForKey state. */ + +#ifdef CONFIG_ISAPNP + if (nopnp == 1) + goto no_pnp; + + for (i=0; el3_isapnp_adapters[i].vendor != 0; i++) { + struct pci_dev *idev = NULL; + int j; + while ((idev = isapnp_find_dev(NULL, + el3_isapnp_adapters[i].vendor, + el3_isapnp_adapters[i].function, + idev))) { + idev->prepare(idev); + /* Deactivation is needed if the driver was called + with "nopnp=1" before, does not harm if not. */ + idev->deactivate(idev); + idev->activate(idev); + if (!idev->resource[0].start || check_region(idev->resource[0].start,16)) + continue; + ioaddr = idev->resource[0].start; + irq = idev->irq_resource[0].start; + if (el3_debug > 3) + printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n", + el3_isapnp_adapters[i].name, ioaddr, irq); + EL3WINDOW(0); + for (j = 0; j < 3; j++) + el3_isapnp_phys_addr[pnp_cards][j] = + phys_addr[j] = + htons(read_eeprom(ioaddr, j)); + if_port = read_eeprom(ioaddr, 8) >> 14; + pnp_cards++; + goto found; + } + } +no_pnp: +#endif + /* Select an open I/O location at 0x1*0 to do contention select. */ for ( ; id_port < 0x200; id_port += 0x10) { if (check_region(id_port, 1)) @@ -312,6 +370,28 @@ phys_addr[i] = htons(id_read_eeprom(i)); } +#ifdef CONFIG_ISAPNP + if (nopnp == 0) { + /* The ISA PnP 3c509 cards respond to the ID sequence. + This check is needed in order not to register them twice. */ + for (i = 0; i < pnp_cards; i++) { + if (phys_addr[0] == el3_isapnp_phys_addr[i][0] && + phys_addr[1] == el3_isapnp_phys_addr[i][1] && + phys_addr[2] == el3_isapnp_phys_addr[i][2]) + { + if (el3_debug > 3) + printk("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", + phys_addr[0] & 0xff, phys_addr[0] >> 8, + phys_addr[1] & 0xff, phys_addr[1] >> 8, + phys_addr[2] & 0xff, phys_addr[2] >> 8); + /* Set the adaptor tag so that the next card can be found. */ + outb(0xd0 + ++current_tag, id_port); + goto no_pnp; + } + } + } +#endif + { unsigned int iobase = id_read_eeprom(8); if_port = iobase >> 14; @@ -357,8 +437,8 @@ { const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; - printk("%s: 3c509 at %#3.3lx tag %d, %s port, address ", - dev->name, dev->base_addr, current_tag, if_names[dev->if_port]); + printk("%s: 3c509 at %#3.3lx, %s port, address ", + dev->name, dev->base_addr, if_names[dev->if_port]); } /* Read in the station address. */ @@ -387,6 +467,8 @@ dev->stop = &el3_close; dev->get_stats = &el3_get_stats; dev->set_multicast_list = &set_multicast_list; + dev->tx_timeout = el3_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; /* Fill in the generic fields of the device structure. */ ether_setup(dev); @@ -481,9 +563,7 @@ outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; + netif_start_queue(dev); outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ @@ -503,28 +583,32 @@ return 0; /* Always succeed */ } -static int -el3_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void +el3_tx_timeout (struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < TX_TIMEOUT) - return 1; - printk("%s: transmit timed out, Tx_status %2.2x status %4.4x " - "Tx FIFO room %d.\n", - dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS), - inw(ioaddr + TX_FREE)); - lp->stats.tx_errors++; - dev->trans_start = jiffies; - /* Issue TX_RESET and TX_START commands. */ - outw(TxReset, ioaddr + EL3_CMD); - outw(TxEnable, ioaddr + EL3_CMD); - dev->tbusy = 0; - } + printk("%s: transmit timed out, Tx_status %2.2x status %4.4x " + "Tx FIFO room %d.\n", + dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS), + inw(ioaddr + TX_FREE)); + lp->stats.tx_errors++; + dev->trans_start = jiffies; + /* Issue TX_RESET and TX_START commands. */ + outw(TxReset, ioaddr + EL3_CMD); + outw(TxEnable, ioaddr + EL3_CMD); + netif_start_queue(dev); +} + + +static int +el3_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; lp->stats.tx_bytes += skb->len; @@ -551,47 +635,37 @@ } #endif #endif - /* Avoid timer-based retransmission conflicts. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); - else { - /* - * We lock the driver against other processors. Note - * we don't need to lock versus the IRQ as we suspended - * that. This means that we lose the ability to take - * an RX during a TX upload. That sucks a bit with SMP - * on an original 3c509 (2K buffer) - * - * Using disable_irq stops us crapping on other - * time sensitive devices. - */ - -#ifdef __SMP__ - disable_irq_nosync(dev->irq); - spin_lock(&lp->lock); -#endif + /* + * We lock the driver against other processors. Note + * we don't need to lock versus the IRQ as we suspended + * that. This means that we lose the ability to take + * an RX during a TX upload. That sucks a bit with SMP + * on an original 3c509 (2K buffer) + * + * Using disable_irq stops us crapping on other + * time sensitive devices. + */ + + spin_lock_irqsave(&lp->lock, flags); - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0x00, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ + /* Put out the doubleword header... */ + outw(skb->len, ioaddr + TX_FIFO); + outw(0x00, ioaddr + TX_FIFO); + /* ... and the packet rounded to a doubleword. */ #ifdef __powerpc__ - outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); + outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); #else - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); + outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); #endif - dev->trans_start = jiffies; - if (inw(ioaddr + TX_FREE) > 1536) { - dev->tbusy = 0; - } else - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); -#ifdef __SMP__ - spin_unlock(&lp->lock); - enable_irq(dev->irq); -#endif - } + dev->trans_start = jiffies; + if (inw(ioaddr + TX_FREE) > 1536) + netif_start_queue(dev); + else + /* Interrupt us when the FIFO has room for max-sized packet. */ + outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); + + spin_unlock_irqrestore(&lp->lock, flags); dev_kfree_skb (skb); @@ -627,10 +701,6 @@ lp = (struct el3_private *)dev->priv; spin_lock(&lp->lock); - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = 1; - ioaddr = dev->base_addr; if (el3_debug > 4) { @@ -649,8 +719,7 @@ printk(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue (dev); } if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) { /* Handle all uncommon interrupts. */ @@ -701,7 +770,6 @@ inw(ioaddr + EL3_STATUS)); } spin_unlock(&lp->lock); - dev->interrupt = 0; return; } @@ -862,8 +930,7 @@ if (el3_debug > 2) printk("%s: Shutting down ethercard.\n", dev->name); - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); /* Turn off statistics ASAP. We update lp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -902,6 +969,7 @@ MODULE_PARM(irq,"1-8i"); MODULE_PARM(xcvr,"1-8i"); MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(nopnp, "i"); int init_module(void) diff -u --recursive --new-file v2.3.42/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.3.42/linux/drivers/net/3c523.c Wed Aug 18 11:36:41 1999 +++ linux/drivers/net/3c523.c Thu Feb 10 12:34:51 2000 @@ -177,7 +177,7 @@ if(!p->scb->cmd) break; \ DELAY_16(); \ if(i == 1023) { \ - printk("%s:%d: scb_cmd timed out .. resetting i82586\n",\ + printk(KERN_WARNING "%s:%d: scb_cmd timed out .. resetting i82586\n",\ dev->name,__LINE__); \ elmc_id_reset586(); } } } @@ -186,6 +186,7 @@ static int elmc_close(struct net_device *dev); static int elmc_send_packet(struct sk_buff *, struct net_device *); static struct net_device_stats *elmc_get_stats(struct net_device *dev); +static void elmc_timeout(struct net_device *dev); #ifdef ELMC_MULTICAST static void set_multicast_list(struct net_device *dev); #endif @@ -270,17 +271,10 @@ static int elmc_close(struct net_device *dev) { + netif_stop_queue(dev); elmc_id_reset586(); /* the hard way to stop the receiver */ - free_irq(dev->irq, dev); - - dev->start = 0; - dev->tbusy = 0; - -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif - return 0; } @@ -296,22 +290,15 @@ if (request_irq(dev->irq, &elmc_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, "3c523", dev) ) { - printk("%s: couldn't get irq %d\n", dev->name, dev->irq); + printk(KERN_ERR "%s: couldn't get irq %d\n", dev->name, dev->irq); elmc_id_reset586(); return -EAGAIN; } alloc586(dev); init586(dev); startrecv586(dev); - - dev->interrupt = 0; - dev->tbusy = 0; - dev->start = 1; - -#ifdef MODULE + netif_wake_queue(dev); MOD_INC_USE_COUNT; -#endif - return 0; /* most done by init */ } @@ -384,7 +371,7 @@ DELAY(2); if (p->iscp->busy) { - printk("%s: Init-Problems (alloc).\n", dev->name); + printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name); } memset((char *) p->scb, 0, sizeof(struct scb_struct)); } @@ -466,7 +453,7 @@ mca_set_adapter_procfn(slot, (MCA_ProcFn) elmc_getinfo, dev); /* if we get this far, adapter has been found - carry on */ - printk("%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1); + printk(KERN_INFO "%s: 3c523 adapter found in slot %d\n", dev->name, slot + 1); /* Now we extract configuration info from the card. The 3c523 provides information in two of the POS registers, but @@ -510,7 +497,7 @@ ((struct priv *) (dev->priv))->slot = slot; - printk("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, + printk(KERN_INFO "%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision, dev->base_addr); /* Determine if we're using the on-board transceiver (i.e. coax) or @@ -532,7 +519,7 @@ size = 0x4000; /* check for 16K mem */ if (!check586(dev, dev->mem_start, size)) { - printk("%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, + printk(KERN_ERR "%s: memprobe, Can't find memory at 0x%lx!\n", dev->name, dev->mem_start); release_region(dev->base_addr, ELMC_IO_EXTENT); return ENODEV; @@ -548,13 +535,13 @@ ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16; /* dump all the assorted information */ - printk("%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name, + printk(KERN_INFO "%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name, dev->irq, dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end - 1); /* The hardware address for the 3c523 is stored in the first six bytes of the IO address. */ - printk("%s: hardware address ", dev->name); + printk(KERN_INFO "%s: hardware address ", dev->name); for (i = 0; i < 6; i++) { dev->dev_addr[i] = inb(dev->base_addr + i); printk(" %02x", dev->dev_addr[i]); @@ -565,6 +552,8 @@ dev->stop = &elmc_close; dev->get_stats = &elmc_get_stats; dev->hard_start_xmit = &elmc_send_packet; + dev->tx_timeout = &elmc_timeout; + dev->watchdog_timeo = HZ; #ifdef ELMC_MULTICAST dev->set_multicast_list = &set_multicast_list; #else @@ -573,10 +562,6 @@ ether_setup(dev); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 0; - /* note that we haven't actually requested the IRQ from the kernel. That gets done in elmc_open(). I'm not sure that's such a good idea, but it works, so I'll go with it. */ @@ -640,7 +625,7 @@ } if ((cfg_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_COMPL | STAT_OK)) { - printk("%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status); + printk(KERN_WARNING "%s (elmc): configure command failed: %x\n", dev->name, cfg_cmd->cmd_status); return 1; } /* @@ -666,7 +651,7 @@ } if ((ias_cmd->cmd_status & (STAT_OK | STAT_COMPL)) != (STAT_OK | STAT_COMPL)) { - printk("%s (elmc): individual address setup command failed: %04x\n", dev->name, ias_cmd->cmd_status); + printk(KERN_WARNING "%s (elmc): individual address setup command failed: %04x\n", dev->name, ias_cmd->cmd_status); return 1; } /* @@ -687,7 +672,7 @@ s = jiffies; while (!(tdr_cmd->cmd_status & STAT_COMPL)) { if (jiffies - s > 30*HZ/100) { - printk("%s: %d Problems while running the TDR.\n", dev->name, __LINE__); + printk(KERN_WARNING "%s: %d Problems while running the TDR.\n", dev->name, __LINE__); result = 1; break; } @@ -703,14 +688,14 @@ if (result & TDR_LNK_OK) { /* empty */ } else if (result & TDR_XCVR_PRB) { - printk("%s: TDR: Transceiver problem!\n", dev->name); + printk(KERN_WARNING "%s: TDR: Transceiver problem!\n", dev->name); } else if (result & TDR_ET_OPN) { - printk("%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK); + printk(KERN_WARNING "%s: TDR: No correct termination %d clocks away.\n", dev->name, result & TDR_TIMEMASK); } else if (result & TDR_ET_SRT) { if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */ - printk("%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK); + printk(KERN_WARNING "%s: TDR: Detected a short circuit %d clocks away.\n", dev->name, result & TDR_TIMEMASK); } else { - printk("%s: TDR: Unknown status %04x\n", dev->name, result); + printk(KERN_WARNING "%s: TDR: Unknown status %04x\n", dev->name, result); } } /* @@ -754,11 +739,11 @@ /* I don't understand this: do we really need memory after the init? */ int len = ((char *) p->iscp - (char *) ptr - 8) / 6; if (len <= 0) { - printk("%s: Ooooops, no memory for MC-Setup!\n", dev->name); + printk(KERN_ERR "%s: Ooooops, no memory for MC-Setup!\n", dev->name); } else { if (len < num_addrs) { num_addrs = len; - printk("%s: Sorry, can only apply %d MC-Address(es).\n", + printk(KERN_WARNING "%s: Sorry, can only apply %d MC-Address(es).\n", dev->name, num_addrs); } mc_cmd = (struct mcsetup_cmd_struct *) ptr; @@ -779,7 +764,7 @@ break; } if (!(mc_cmd->cmd_status & STAT_COMPL)) { - printk("%s: Can't apply multicast-address-list.\n", dev->name); + printk(KERN_WARNING "%s: Can't apply multicast-address-list.\n", dev->name); } } } @@ -792,7 +777,7 @@ p->xmit_buffs[i] = (struct tbd_struct *) ptr; /* TBD */ ptr = (char *) ptr + sizeof(struct tbd_struct); if ((void *) ptr > (void *) p->iscp) { - printk("%s: not enough shared-mem for your configuration!\n", dev->name); + printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n", dev->name); return 1; } memset((char *) (p->xmit_cmds[i]), 0, sizeof(struct transmit_cmd_struct)); @@ -882,9 +867,9 @@ struct priv *p; if (dev == NULL) { - printk("elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2)); + printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2)); return; - } else if (!dev->start) { + } else if (!test_bit(LINK_STATE_START, &dev->state)) { /* The 3c523 has this habit of generating interrupts during the reset. I'm not sure if the ni52 has this same problem, but it's really annoying if we haven't finished initializing it. I was @@ -901,8 +886,6 @@ p = (struct priv *) dev->priv; - dev->interrupt = 1; - while ((stat = p->scb->status & STAT_MASK)) { p->scb->cmd = stat; @@ -919,8 +902,8 @@ #ifndef NO_NOPCOMMANDS if (stat & STAT_CNA) { /* CU went 'not ready' */ - if (dev->start) { - printk("%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); + if (test_bit(LINK_STATE_START, &dev->state)) { + printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); } } #endif @@ -935,7 +918,7 @@ p->scb->cmd = RUC_RESUME; elmc_attn586(); } else { - printk("%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); + printk(KERN_WARNING "%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); elmc_rnr_int(dev); } } @@ -944,8 +927,6 @@ break; } } - - dev->interrupt = 0; } /******************************************************* @@ -980,11 +961,11 @@ p->stats.rx_dropped++; } } else { - printk("%s: received oversized frame.\n", dev->name); + printk(KERN_WARNING "%s: received oversized frame.\n", dev->name); p->stats.rx_dropped++; } } else { /* frame !(ok), only with 'save-bad-frames' */ - printk("%s: oops! rfd-error-status: %04x\n", dev->name, status); + printk(KERN_WARNING "%s: oops! rfd-error-status: %04x\n", dev->name, status); p->stats.rx_errors++; } p->rfd_top->status = 0; @@ -1013,7 +994,7 @@ alloc_rfa(dev, (char *) p->rfd_first); startrecv586(dev); /* restart RU */ - printk("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status); + printk(KERN_WARNING "%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status); } @@ -1028,7 +1009,7 @@ status = p->xmit_cmds[p->xmit_last]->cmd_status; if (!(status & STAT_COMPL)) { - printk("%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); + printk(KERN_WARNING "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); } if (status & STAT_OK) { p->stats.tx_packets++; @@ -1036,18 +1017,18 @@ } else { p->stats.tx_errors++; if (status & TCMD_LATECOLL) { - printk("%s: late collision detected.\n", dev->name); + printk(KERN_WARNING "%s: late collision detected.\n", dev->name); p->stats.collisions++; } else if (status & TCMD_NOCARRIER) { p->stats.tx_carrier_errors++; - printk("%s: no carrier detected.\n", dev->name); + printk(KERN_WARNING "%s: no carrier detected.\n", dev->name); } else if (status & TCMD_LOSTCTS) { - printk("%s: loss of CTS detected.\n", dev->name); + printk(KERN_WARNING "%s: loss of CTS detected.\n", dev->name); } else if (status & TCMD_UNDERRUN) { p->stats.tx_fifo_errors++; - printk("%s: DMA underrun detected.\n", dev->name); + printk(KERN_WARNING "%s: DMA underrun detected.\n", dev->name); } else if (status & TCMD_MAXCOLL) { - printk("%s: Max. collisions exceeded.\n", dev->name); + printk(KERN_WARNING "%s: Max. collisions exceeded.\n", dev->name); p->stats.collisions += 16; } } @@ -1058,8 +1039,7 @@ } #endif - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); } /*********************************************************** @@ -1077,6 +1057,37 @@ } /****************************************************** + * timeout + */ + +static void elmc_timeout(struct net_device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + /* COMMAND-UNIT active? */ + if (p->scb->status & CU_ACTIVE) { +#ifdef DEBUG + printk("%s: strange ... timeout with CU active?!?\n", dev->name); + printk("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, (int) p->xmit_cmds[0]->cmd_status, (int) p->nop_cmds[0]->cmd_status, (int) p->nop_cmds[1]->cmd_status, (int) p->nop_point); +#endif + p->scb->cmd = CUC_ABORT; + elmc_attn586(); + WAIT_4_SCB_CMD(); + p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]); + p->scb->cmd = CUC_START; + elmc_attn586(); + WAIT_4_SCB_CMD(); + netif_wake_queue(dev); + } else { +#ifdef DEBUG + printk("%s: xmitter timed out, try to restart! stat: %04x\n", dev->name, p->scb->status); + printk("%s: command-stats: %04x %04x\n", dev->name, p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status); +#endif + elmc_close(dev); + elmc_open(dev); + } +} + +/****************************************************** * send frame */ @@ -1088,103 +1099,63 @@ #endif struct priv *p = (struct priv *) dev->priv; - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) { - return 1; - } - /* COMMAND-UNIT active? */ - if (p->scb->status & CU_ACTIVE) { - dev->tbusy = 0; -#ifdef DEBUG - printk("%s: strange ... timeout with CU active?!?\n", dev->name); - printk("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, (int) p->xmit_cmds[0]->cmd_status, (int) p->nop_cmds[0]->cmd_status, (int) p->nop_cmds[1]->cmd_status, (int) p->nop_point); -#endif - p->scb->cmd = CUC_ABORT; - elmc_attn586(); - WAIT_4_SCB_CMD(); - p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]); - p->scb->cmd = CUC_START; - elmc_attn586(); - WAIT_4_SCB_CMD(); - dev->trans_start = jiffies; - return 0; - } else { -#ifdef DEBUG - printk("%s: xmitter timed out, try to restart! stat: %04x\n", dev->name, p->scb->status); - printk("%s: command-stats: %04x %04x\n", dev->name, p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status); -#endif - elmc_close(dev); - elmc_open(dev); - } - dev->trans_start = jiffies; - return 0; - } - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - } else { - memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len); - len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + netif_stop_queue(dev); + + memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len); + len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; #if (NUM_XMIT_BUFFS == 1) #ifdef NO_NOPCOMMANDS - p->xmit_buffs[0]->size = TBD_LAST | len; - for (i = 0; i < 16; i++) { - p->scb->cbl_offset = make16(p->xmit_cmds[0]); - p->scb->cmd = CUC_START; - p->xmit_cmds[0]->cmd_status = 0; - + p->xmit_buffs[0]->size = TBD_LAST | len; + for (i = 0; i < 16; i++) { + p->scb->cbl_offset = make16(p->xmit_cmds[0]); + p->scb->cmd = CUC_START; + p->xmit_cmds[0]->cmd_status = 0; elmc_attn586(); - dev->trans_start = jiffies; - if (!i) { - dev_kfree_skb(skb); - } - WAIT_4_SCB_CMD(); - if ((p->scb->status & CU_ACTIVE)) { /* test it, because CU sometimes doesn't start immediately */ - break; - } - if (p->xmit_cmds[0]->cmd_status) { - break; - } - if (i == 15) { - printk("%s: Can't start transmit-command.\n", dev->name); - } + dev->trans_start = jiffies; + if (!i) { + dev_kfree_skb(skb); + } + WAIT_4_SCB_CMD(); + if ((p->scb->status & CU_ACTIVE)) { /* test it, because CU sometimes doesn't start immediately */ + break; + } + if (p->xmit_cmds[0]->cmd_status) { + break; + } + if (i == 15) { + printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name); } + } #else - next_nop = (p->nop_point + 1) & 0x1; - p->xmit_buffs[0]->size = TBD_LAST | len; - - p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link - = make16((p->nop_cmds[next_nop])); - p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0; - - p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); - dev->trans_start = jiffies; - p->nop_point = next_nop; - dev_kfree_skb(skb); + next_nop = (p->nop_point + 1) & 0x1; + p->xmit_buffs[0]->size = TBD_LAST | len; + + p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link + = make16((p->nop_cmds[next_nop])); + p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0; + + p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); + dev->trans_start = jiffies; + p->nop_point = next_nop; + dev_kfree_skb(skb); #endif #else - p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; - if ((next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS) { - next_nop = 0; - } - p->xmit_cmds[p->xmit_count]->cmd_status = 0; - p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link - = make16((p->nop_cmds[next_nop])); - p->nop_cmds[next_nop]->cmd_status = 0; - + p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; + if ((next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS) { + next_nop = 0; + } + p->xmit_cmds[p->xmit_count]->cmd_status = 0; + p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link + = make16((p->nop_cmds[next_nop])); + p->nop_cmds[next_nop]->cmd_status = 0; p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count])); - dev->trans_start = jiffies; - p->xmit_count = next_nop; - - cli(); - if (p->xmit_count != p->xmit_last) { - dev->tbusy = 0; - } - sti(); - dev_kfree_skb(skb); + dev->trans_start = jiffies; + p->xmit_count = next_nop; + if (p->xmit_count != p->xmit_last) + netif_wake_queue(dev); + dev_kfree_skb(skb); #endif - } return 0; } diff -u --recursive --new-file v2.3.42/linux/drivers/net/3c527.c linux/drivers/net/3c527.c --- v2.3.42/linux/drivers/net/3c527.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/3c527.c Thu Feb 10 12:34:51 2000 @@ -1,4 +1,3 @@ - /* 3c527.c: 3Com Etherlink/MC32 driver for Linux * * (c) Copyright 1998 Red Hat Software Inc @@ -18,11 +17,8 @@ static const char *version = "3c527.c:v0.07 2000/01/18 Alan Cox (alan@redhat.com)\n"; -/* - * Things you need - * o The databook. - * - * Traps for the unwary +/** + * DOC: Traps for the unwary * * The diagram (Figure 1-1) and the POS summary disagree with the * "Interrupt Level" section in the manual. @@ -30,6 +26,32 @@ * The documentation in places seems to miss things. In actual fact * I've always eventually found everything is documented, it just * requires careful study. + * + * DOC: Theory Of Operation + * + * The 3com 3c527 is a 32bit MCA bus mastering adapter with a large + * amount of on board intelligence that housekeeps a somewhat dumber + * Intel NIC. For performance we want to keep the transmit queue deep + * as the card can transmit packets while fetching others from main + * memory by bus master DMA. Transmission and reception are driven by + * ring buffers. When updating the ring we are required to do some + * housekeeping work using the mailboxes and the command register. + * + * The mailboxes provide a method for sending control requests to the + * card. The transmit mail box is used to update the transmit ring + * pointers and the receive mail box to update the receive ring + * pointers. The exec mailbox allows a variety of commands to be + * executed. Each command must complete before the next is executed. + * Primarily we use the exec mailbox for controlling the multicast lists. + * We have to do a certain amount of interesting hoop jumping as the + * multicast list changes can occur in interrupt state when the card + * has an exec command pending. We defer such events until the command + * completion interrupt. + * + * The control register is used to pass status information. It tells us + * the transmit and receive status for packets and allows us to control + * the card operation mode. You must stop the card when emptying the + * receive ring, or you will race with the ring buffer and lose packets. */ #include @@ -135,6 +157,7 @@ static int mc32_probe1(struct net_device *dev, int ioaddr); static int mc32_open(struct net_device *dev); +static void mc32_timeout(struct net_device *dev); static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev); static void mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int mc32_close(struct net_device *dev); @@ -143,12 +166,14 @@ static void mc32_reset_multicast_list(struct net_device *dev); -/* - * Check for a network adaptor of this type, and return '0' iff 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). +/** + * mc32_probe: + * @dev: device to probe + * + * Because MCA bus is a real bus and we can scan for cards we could do a + * single scan for all boards here. Right now we use the passed in device + * structure and scan for only one board. This needs fixing for modules + * in paticular. */ int __init mc32_probe(struct net_device *dev) @@ -182,11 +207,17 @@ return -ENODEV; } -/* - * This is the real probe routine. Linux has a history of friendly device - * probes on the ISA bus. A good device probes avoids doing writes, and - * verifies that the correct device exists and functions. +/** + * mc32_probe1: + * @dev: Device structure to fill in + * @slot: The MCA bus slot being used by this card + * + * Decode the slot data and configure the card structures. Having done this we + * can reset the card and configure it. The card does a full self test cycle + * in firmware so we have to wait for it to return and post us either a + * failure case or some addresses we use to find the board internals. */ + static int __init mc32_probe1(struct net_device *dev, int slot) { static unsigned version_printed = 0; @@ -239,13 +270,14 @@ return -ENODEV; } - /* Allocate a new 'dev' if needed. */ - if (dev == NULL) { - /* - * Don't allocate the private data here, it is done later - * This makes it easier to free the memory when this driver - * is used as a module. - */ + /* + * Don't allocate the private data here, it is done later + * This makes it easier to free the memory when this driver + * is used as a module. + */ + + if(dev==NULL) + { dev = init_etherdev(0, 0); if (dev == NULL) return -ENOMEM; @@ -425,6 +457,8 @@ dev->hard_start_xmit = mc32_send_packet; dev->get_stats = mc32_get_stats; dev->set_multicast_list = mc32_set_multicast_list; + dev->tx_timeout = mc32_timeout; + dev->watchdog_timeo = HZ*5; /* Board does all the work */ lp->rx_halted = 1; lp->tx_halted = 1; @@ -435,8 +469,13 @@ } -/* - * Polled command stuff +/** + * mc32_ring_poll: + * @dev: The device to wait for + * + * Wait until a command we issues to the control register is completed. + * This actually takes very little time at all, which is fortunate as + * we often have to busy wait it. */ static void mc32_ring_poll(struct net_device *dev) @@ -446,25 +485,20 @@ } -/* - * Send exec commands. This requires a bit of explaining. - * - * You feed the card a command, you wait, it interrupts you get a - * reply. All well and good. The complication arises because you use - * commands for filter list changes which come in at bh level from things - * like IPV6 group stuff. - * - * We have a simple state machine - * - * 0 - nothing issued - * 1 - command issued, wait reply - * 2 - reply waiting - reader then goes to state 0 - * 3 - command issued, trash reply. In which case the irq - * takes it back to state 0 - */ -/* - * Send command from interrupt state +/** + * mc32_command_nowait: + * @dev: The 3c527 to issue the command to + * @cmd: The command word to write to the mailbox + * @data: A data block if the command expects one + * @len: Length of the data block + * + * Send a command from interrupt state. If there is a command currently + * being executed then we return an error of -1. It simply isnt viable + * to wait around as commands may be slow. Providing we get in then + * we send the command and busy wait for the board to acknowledge that + * a command request is pending. We do not wait for the command to + * complete, just for the card to admit to noticing it. */ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) @@ -488,7 +522,35 @@ } -/* +/** + * mc32_command: + * @dev: The 3c527 card to issue the command to + * @cmd: The command word to write to the mailbox + * @data: A data block if the command expects one + * @len: Length of the data block + * + * Sends exec commands in a user context. This permits us to wait around + * for the replies and also to wait for the command buffer to complete + * from a previous command before we execute our command. After our + * command completes we will complete any pending multicast reload + * we blocked off by hogging the exec buffer. + * + * You feed the card a command, you wait, it interrupts you get a + * reply. All well and good. The complication arises because you use + * commands for filter list changes which come in at bh level from things + * like IPV6 group stuff. + * + * We have a simple state machine + * + * 0 - nothing issued + * + * 1 - command issued, wait reply + * + * 2 - reply waiting - reader then goes to state 0 + * + * 3 - command issued, trash reply. In which case the irq + * takes it back to state 0 + * * Send command and block for results. On completion spot and reissue * multicasts */ @@ -548,8 +610,13 @@ } -/* - * RX abort +/** + * mc32_rx_abort: + * @dev: 3c527 to abort + * + * Peforms a receive abort sequence on the card. In fact after some + * experimenting we now simply tell the card to suspend reception. When + * issuing aborts occasionally odd things happened. */ static void mc32_rx_abort(struct net_device *dev) @@ -564,8 +631,13 @@ } -/* - * RX enable +/** + * mc32_rx_begin: + * @dev: 3c527 to enable + * + * We wait for any pending command to complete and then issue + * a start reception command to the board itself. At this point + * receive handling continues as it was before. */ static void mc32_rx_begin(struct net_device *dev) @@ -582,6 +654,18 @@ lp->rx_halted=0; } +/** + * mc32_tx_abort: + * @dev: 3c527 to abort + * + * Peforms a receive abort sequence on the card. In fact after some + * experimenting we now simply tell the card to suspend transmits . When + * issuing aborts occasionally odd things happened. In theory we want + * an abort to be sure we can recycle our buffers. As it happens we + * just have to be careful to shut the card down on close, and + * boot it carefully from scratch on setup. + */ + static void mc32_tx_abort(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; @@ -625,8 +709,16 @@ lp->tx_skb_top=lp->tx_skb_end=0; } -/* - * TX enable +/** + * mc32_tx_begin: + * @dev: 3c527 to enable + * + * We wait for any pending command to complete and then issue + * a start transmit command to the board itself. At this point + * transmit handling continues as it was before. The ring must + * be setup before you do this and must have an end marker in it. + * It turns out we can avoid issuing this specific command when + * doing our setup so we avoid it. */ static void mc32_tx_begin(struct net_device *dev) @@ -648,8 +740,17 @@ } -/* - * Load the rx ring +/** + * mc32_load_rx_ring: + * @dev: 3c527 to build the ring for + * + * The card setups up the receive ring for us. We are required to + * use the ring it provides although we can change the size of the + * ring. + * + * We allocate an sk_buff for each ring entry in turn and set the entry + * up for a single non s/g buffer. The first buffer we mark with the + * end marker bits. Finally we clear the rx mailbox. */ static int mc32_load_rx_ring(struct net_device *dev) @@ -686,6 +787,15 @@ return 0; } +/** + * mc32_flush_rx_ring: + * @lp: Local data of 3c527 to flush the rx ring of + * + * Free the buffer for each ring slot. Because of the receive + * algorithm we use the ring will always be loaded will a full set + * of buffers. + */ + static void mc32_flush_rx_ring(struct mc32_local *lp) { int i; @@ -693,6 +803,15 @@ kfree_skb(lp->rx_skb[i]); } +/** + * mc32_flush_tx_ring: + * @lp: Local data of 3c527 to flush the tx ring of + * + * We have to consider two cases here. We want to free the pending + * buffers only. If the ring buffer head is past the start then the + * ring segment we wish to free wraps through zero. + */ + static void mc32_flush_tx_ring(struct mc32_local *lp) { int i; @@ -711,9 +830,20 @@ } } -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. +/** + * mc32_open + * @dev: device to open + * + * The user is trying to bring the card into ready state. This requires + * a brief dialogue with the card. Firstly we enable interrupts and then + * 'indications'. Without these enabled the card doesn't bother telling + * us what it has done. This had me puzzled for a week. + * + * We then load the network address and multicast filters. Turn on the + * workaround mode. This works around a bug in the 82586 - it asks the + * firmware to do so. It has a performance hit but is needed on busy + * [read most] lans. We load the ring with buffers then we kick it + * all off. */ static int mc32_open(struct net_device *dev) @@ -723,10 +853,6 @@ u8 one=1; u8 regs; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - /* * Interrupts enabled */ @@ -775,100 +901,138 @@ mc32_rx_begin(dev); mc32_tx_begin(dev); - + + netif_wake_queue(dev); MOD_INC_USE_COUNT; return 0; } +/** + * mc32_timeout: + * @dev: 3c527 that timed out + * + * Handle a timeout on transmit from the 3c527. This normally means + * bad things as the hardware handles cable timeouts and mess for + * us. + * + */ + +static void mc32_timeout(struct net_device *dev) +{ + printk(KERN_WARNING "%s: transmit timed out?\n", dev->name); + /* Try to restart the adaptor. */ + netif_wake_queue(dev); +} + +/** + * mc32_send_packet: + * @skb: buffer to transmit + * @dev: 3c527 to send it out of + * + * Transmit a buffer. This normally means throwing the buffer onto + * the transmit queue as the queue is quite large. If the queue is + * full then we set tx_busy and return. Once the interrupt handler + * gets messages telling it to reclaim transmit queue entries we will + * clear tx_busy and the kernel will start calling this again. + * + * We use cli rather than spinlocks. Since I have no access to an SMP + * MCA machine I don't plan to change it. It is probably the top + * performance hit for this driver on SMP however. + */ + static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - - if (dev->tbusy) { - /* - * If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) - return 1; - printk(KERN_WARNING "%s: transmit timed out?\n", dev->name); - /* Try to restart the adaptor. */ - dev->tbusy=0; - dev->trans_start = jiffies; - } - - /* - * Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - dev_kfree_skb(skb); - } - else - { - unsigned long flags; + unsigned long flags; - u16 tx_head; - volatile struct skb_header *p, *np; + u16 tx_head; + volatile struct skb_header *p, *np; - save_flags(flags); - cli(); + netif_stop_queue(dev); + + save_flags(flags); + cli(); - if(atomic_read(&lp->tx_count)==0) - { - dev->tbusy=1; - restore_flags(flags); - return 1; - } - - tx_head = lp->tx_box->data[0]; - atomic_dec(&lp->tx_count); + if(atomic_read(&lp->tx_count)==0) + { + restore_flags(flags); + return 1; + } - /* We will need this to flush the buffer out */ - - lp->tx_skb[lp->tx_skb_end] = skb; - lp->tx_skb_end++; - lp->tx_skb_end&=(TX_RING_MAX-1); - - /* P is the last sending/sent buffer as a pointer */ - p=(struct skb_header *)bus_to_virt(lp->base+tx_head); - - /* NP is the buffer we will be loading */ - np=(struct skb_header *)bus_to_virt(lp->base+p->next); + tx_head = lp->tx_box->data[0]; + atomic_dec(&lp->tx_count); + /* We will need this to flush the buffer out */ + + lp->tx_skb[lp->tx_skb_end] = skb; + lp->tx_skb_end++; + lp->tx_skb_end&=(TX_RING_MAX-1); + + /* P is the last sending/sent buffer as a pointer */ + p=(struct skb_header *)bus_to_virt(lp->base+tx_head); + + /* NP is the buffer we will be loading */ + np=(struct skb_header *)bus_to_virt(lp->base+p->next); - np->control |= (1<<6); /* EOL */ - wmb(); + np->control |= (1<<6); /* EOL */ + wmb(); - np->length = skb->len; + np->length = skb->len; - if(np->length < 60) - np->length = 60; + if(np->length < 60) + np->length = 60; - np->data = virt_to_bus(skb->data); - np->status = 0; - np->control = (1<<7)|(1<<6); /* EOP EOL */ - wmb(); - - p->status = 0; - p->control &= ~(1<<6); - - dev->tbusy = 0; /* Keep feeding me */ + np->data = virt_to_bus(skb->data); + np->status = 0; + np->control = (1<<7)|(1<<6); /* EOP EOL */ + wmb(); - lp->tx_box->mbox=0; - restore_flags(flags); - } + p->status = 0; + p->control &= ~(1<<6); + + lp->tx_box->mbox=0; + restore_flags(flags); + + netif_wake_queue(dev); return 0; } +/** + * mc32_update_stats: + * @dev: 3c527 to service + * + * When the board signals us that its statistics need attention we + * should query the table and clear it. In actual fact we currently + * track all our statistics in software and I haven't implemented it yet. + */ + static void mc32_update_stats(struct net_device *dev) { } - +/** + * mc32_rx_ring: + * @dev: 3c527 that needs its receive ring processing + * + * We have received one or more indications from the card that + * a receive has completed. The ring buffer thus contains dirty + * entries. Firstly we tell the card to stop receiving, then We walk + * the ring from the first filled entry, which is pointed to by the + * card rx mailbox and for each completed packet we will either copy + * it and pass it up the stack or if the packet is near MTU sized we + * allocate another buffer and flip the old one up the stack. + * + * We must succeed in keeping a buffer on the ring. If neccessary we + * will toss a received packet rather than lose a ring entry. Once the + * first packet that is unused is found we reload the mailbox with the + * buffer so that the card knows it can use the buffers again. Finally + * we set it receiving again. + * + * We must stop reception during the ring walk. I thought it would be + * neat to avoid it by clever tricks, but it turns out the event order + * on the card means you have to play by the manual. + */ + static void mc32_rx_ring(struct net_device *dev) { struct mc32_local *lp=dev->priv; @@ -877,6 +1041,12 @@ volatile struct skb_header *p; u16 base; u16 top; + + /* Halt RX before walking the ring */ + + while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); + outb(3<<3, ioaddr+HOST_CMD); + while(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR); top = base = lp->rx_box->data[0]; do @@ -927,13 +1097,6 @@ } while(x++<48); - /* - * This is curious. It seems the receive stop and receive continue - * commands race against each other, even though we poll for - * command ready to be issued. The delay is hackish but is a workaround - * while I investigate in depth - */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->rx_box->mbox=0; lp->rx_box->data[0] = top; @@ -941,10 +1104,20 @@ } -/* - * The typical workload of the driver: - * Handle the network interface interrupts. +/** + * mc32_interrupt: + * @irq: Interrupt number + * @dev_id: 3c527 that requires servicing + * @regs: Registers (unused) + * + * The 3c527 interrupts us for four reasons. The command register + * contains the message it wishes to send us packed into a single + * byte field. We keep reading status entries until we have processed + * all the transmit and control items, but simply count receive + * reports. When the receive reports are in we can call the mc32_rx_ring + * and empty the ring. This saves the overhead of multiple command requests */ + static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; @@ -956,8 +1129,6 @@ printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); return; } - dev->interrupt = 1; - ioaddr = dev->base_addr; lp = (struct mc32_local *)dev->priv; @@ -990,8 +1161,7 @@ lp->tx_skb_top++; lp->tx_skb_top&=(TX_RING_MAX-1); atomic_inc(&lp->tx_count); - dev->tbusy=0; - mark_bh(NET_BH); + netif_wake_queue(dev); break; case 3: /* Halt */ case 4: /* Abort */ @@ -1066,13 +1236,27 @@ if(rx_event) mc32_rx_ring(dev); - dev->interrupt = 0; return; } -/* The inverse routine to mc32_open(). */ - +/** + * mc32_close: + * @dev: 3c527 card to shut down + * + * The 3c527 is a bus mastering device. We must be careful how we + * shut it down. It may also be running shared interrupt so we have + * to be sure to silence it properly + * + * We abort any receive and transmits going on and then wait until + * any pending exec commands have completed in other code threads. + * In theory we can't get here while that is true, in practice I am + * paranoid + * + * We turn off the interrupt enable for the board to be sure it can't + * intefere with other devices. + */ + static int mc32_close(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; @@ -1080,6 +1264,8 @@ u8 regs; u16 one=1; + netif_stop_queue(dev); + /* * Send the indications on command (handy debug check) */ @@ -1105,9 +1291,6 @@ mc32_flush_rx_ring(lp); mc32_flush_tx_ring(lp); - dev->tbusy = 1; - dev->start = 0; - /* Update the statistics here. */ MOD_DEC_USE_COUNT; @@ -1116,9 +1299,14 @@ } -/* - * Get the current statistics. - * This may be called with the card open or closed. +/** + * mc32_get_stats: + * @dev: The 3c527 card to handle + * + * As we currently handle our statistics in software this one is + * easy to handle. With hardware statistics it will get messy + * as the get_stats call will need to send exec mailbox messages and + * need to lock out the multicast reloads. */ static struct net_device_stats *mc32_get_stats(struct net_device *dev) @@ -1127,13 +1315,24 @@ return &lp->net_stats; } -/* - * Set or clear the multicast filter for this adaptor. +/** + * do_mc32_set_multicast_list: + * @dev: 3c527 device to load the list on + * @retry: indicates this is not the first call. + * + * Actually set or clear the multicast filter for this adaptor. The locking + * issues are handled by this routine. We have to track state as it may take + * multiple calls to get the command sequence completed. We just keep trying + * to schedule the loads until we manage to process them all. + * * 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 do_mc32_set_multicast_list(struct net_device *dev, int retry) { struct mc32_local *lp = (struct mc32_local *)dev->priv; @@ -1189,11 +1388,30 @@ } } +/** + * mc32_set_multicast_list: + * @dev: The 3c527 to use + * + * Commence loading the multicast list. This is called when the kernel + * changes the lists. It will override any pending list we are trying to + * load. + */ + static void mc32_set_multicast_list(struct net_device *dev) { do_mc32_set_multicast_list(dev,0); } +/** + * mc32_reset_multicast_list: + * @dev: The 3c527 to use + * + * Attempt the next step in loading the multicast lists. If this attempt + * fails to complete then it will be scheduled and this function called + * again later from elsewhere. + */ + + static void mc32_reset_multicast_list(struct net_device *dev) { do_mc32_set_multicast_list(dev,1); @@ -1208,6 +1426,15 @@ 0, 0, /* I/O address, IRQ */ 0, 0, 0, NULL, mc32_probe }; + +/** + * init_module: + * + * Probe and locate a 3c527 card. This really should probe and locate + * all the 3c527 cards in the machine not just one of them. Yes you can + * insmod multiple modules for now but its a hack. + */ + int init_module(void) { int result; @@ -1218,6 +1445,17 @@ return 0; } +/** + * cleanup_module: + * + * Unloading time. We release the MCA bus resources and the interrupt + * at which point everything is ready to unload. The card must be stopped + * at this point or we would not have been called. When we unload we + * leave the card stopped but not totally shut down. When the card is + * initialized it must be rebooted or the rings reloaded before any + * transmit operations are allowed to start scribbling into memory. + */ + void cleanup_module(void) { int slot; @@ -1227,8 +1465,6 @@ /* * If we don't do this, we can't re-insmod it later. - * Release irq/dma here, when you have jumpered versions and - * allocate them in mc32_probe1(). */ if (this_device.priv) diff -u --recursive --new-file v2.3.42/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.3.42/linux/drivers/net/3c59x.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/net/3c59x.c Thu Feb 10 12:22:03 2000 @@ -1,4 +1,4 @@ -/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */ +/* 3c59x.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */ /* Written 1996-1998 by Donald Becker. @@ -12,10 +12,16 @@ 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 -*/ + + Version history: + 0.99H+lk1.0 - Jeff Garzik + Remove compatibility defines for kernel versions < 2.2.x. + Update for new 2.3.x module interface + + */ static char *version = -"3c59x.c:v0.99H 11/17/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; +"3c59x.c:v0.99H+lk1.0 Feb 9, 2000 The Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -49,22 +55,14 @@ #include #include -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include #include #include #include #include #include +#include #include #include #include @@ -72,9 +70,6 @@ #include #include #include -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -#include -#endif #include /* For NR_IRQS only. */ #include #include @@ -86,35 +81,9 @@ #include -#if (LINUX_VERSION_CODE <= 0x20100) -#ifndef __alpha__ -#define ioremap(a,b) \ - (((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b)) -#define iounmap(v) \ - do { if ((u_long)(v) > 0x100000) vfree(v); } while (0) -#endif -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20138 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#define le32_to_cpu(val) (val) -#define cpu_to_le32(val) (val) -#endif -#if LINUX_VERSION_CODE < 0x20155 -#define PCI_SUPPORT_VER1 -#else #define PCI_SUPPORT_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE); -#else /* Grrr, unneeded incompatible change. */ #define DEV_FREE_SKB(skb) dev_kfree_skb(skb); -#endif -#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver"); MODULE_PARM(debug, "i"); @@ -125,7 +94,6 @@ MODULE_PARM(compaq_ioaddr, "i"); MODULE_PARM(compaq_irq, "i"); MODULE_PARM(compaq_device_id, "i"); -#endif /* Operational parameter that usually are not changed. */ @@ -229,12 +197,12 @@ const char *name; u16 vendor_id, device_id, device_id_mask, flags; int drv_flags, io_size; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); + struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt); }; enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, }; -static struct net_device *vortex_probe1(int pci_bus, int pci_devfn, long ioaddr, int irq, int dev_id, int card_idx); +static struct net_device *vortex_probe1(struct pci_dev *pdev, long ioaddr, int irq, int dev_id, int card_idx); static struct pci_id_info pci_tbl[] = { {"3c590 Vortex 10Mbps", 0x10B7, 0x5900, 0xffff, @@ -426,22 +394,27 @@ struct vortex_private { /* The Rx and Tx rings should be quad-word-aligned. */ - struct boom_rx_desc rx_ring[RX_RING_SIZE]; - struct boom_tx_desc tx_ring[TX_RING_SIZE]; + struct boom_rx_desc* rx_ring; + struct boom_tx_desc* tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; /* The addresses of transmit- and receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct net_device *next_module; void *priv_addr; + dma_addr_t ring_dma; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ + dma_addr_t tx_skb_dma; /* Allocated DMA address for bus master ctrl DMA. */ /* PCI configuration space information. */ u8 pci_bus, pci_devfn; /* PCI bus location, for power management. */ char *cb_fn_base; /* CardBus function status addr space. */ int chip_id; + struct pci_dev *pdev; /* Device for DMA mapping */ /* The remainder are related to chip state, mostly media selection. */ unsigned long in_interrupt; @@ -499,6 +472,7 @@ static void mdio_write(long ioaddr, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void vortex_tx_timeout(struct net_device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev); static int vortex_rx(struct net_device *dev); static int boomerang_rx(struct net_device *dev); @@ -518,7 +492,6 @@ /* A list of all installed Vortex devices, for removing the driver module. */ static struct net_device *root_vortex_dev = NULL; -#ifdef MODULE #ifndef CARDBUS /* Variables to work-around the Compaq PCI BIOS32 problem. */ static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900; @@ -532,18 +505,20 @@ { u16 dev_id, vendor_id; u32 io; - u8 bus, devfn, irq; + u8 irq; struct net_device *dev; + struct pci_dev *pdev; int chip_idx; if (loc->bus != LOC_PCI) return NULL; - bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); - pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); - pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id); - pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); + pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); + if (!pdev) return NULL; + io = pdev->resource[0].start; + irq = pdev->irq; + vendor_id = pdev->vendor; + dev_id = pdev->device; printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n", - bus, devfn, dev_id); + pdev->bus->number, pdev->devfn, dev_id); io &= ~3; if (io == 0 || irq == 0) { printk(KERN_ERR "The 3Com CardBus Ethernet interface was not " @@ -561,7 +536,7 @@ "vortex_attach().\n", vendor_id, dev_id); return NULL; } - dev = vortex_probe1(bus, devfn, io, irq, chip_idx, MAX_UNITS+1); + dev = vortex_probe1(pdev, io, irq, chip_idx, MAX_UNITS+1); if (dev) { dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); strcpy(node->dev_name, dev->name); @@ -604,7 +579,7 @@ #endif /* Cardbus support */ -int init_module(void) +static int __init vortex_init_module (void) { if (vortex_debug) printk(KERN_INFO "%s", version); @@ -616,17 +591,6 @@ #endif } -#else -int tc59x_probe(void) -{ - static int scanned=0; - if(scanned++) - return -ENODEV; - printk(KERN_INFO "%s", version); - return vortex_scan(pci_tbl); -} -#endif /* not MODULE */ - #ifndef CARDBUS static int vortex_scan(struct pci_id_info pci_tbl[]) { @@ -639,7 +603,7 @@ be best done a central PCI probe dispatch, which wouldn't work well with the current structure. So instead we detect 3Com cards in slot order. */ - if (pcibios_present()) { + if (pci_present()) { static int pci_index = 0; unsigned char pci_bus, pci_device_fn; @@ -647,15 +611,16 @@ u16 vendor, device, pci_command, new_command, pwr_cmd; int chip_idx, irq; long ioaddr; + struct pci_dev *pdev; if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); + pdev = pci_find_slot (pci_bus, pci_device_fn); + if (!pdev) continue; + vendor = pdev->vendor; + device = pdev->device; for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) if (vendor == pci_tbl[chip_idx].vendor_id && (device & pci_tbl[chip_idx].device_id_mask) == @@ -671,21 +636,18 @@ } /* Power-up the card. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - 0xe0, &pwr_cmd); + pci_read_config_word(pdev, 0xe0, &pwr_cmd); + if (pwr_cmd & 0x3) { /* Save the ioaddr and IRQ info! */ printk(KERN_INFO " A 3Com network adapter is powered down!" " Setting the power state %4.4x->%4.4x.\n", pwr_cmd, pwr_cmd & ~3); - pcibios_write_config_word(pci_bus, pci_device_fn, - 0xe0, pwr_cmd & ~3); + pci_write_config_word(pdev, 0xe0, pwr_cmd & ~3); printk(KERN_INFO " Setting the IRQ to %d, IOADDR to %#lx.\n", irq, ioaddr); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, irq); - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, ioaddr); + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, ioaddr); } if (ioaddr == 0) { @@ -700,19 +662,18 @@ continue; /* Activate the card. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; if (pci_command != new_command) { printk(KERN_INFO " The PCI BIOS has not enabled the device " "at %d/%d. Updating PCI command %4.4x->%4.4x.\n", pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); + pci_write_config_word(pdev, PCI_COMMAND, new_command); } - dev = vortex_probe1(pci_bus, pci_device_fn, ioaddr, irq, - chip_idx, cards_found); + dev = vortex_probe1(pdev, ioaddr, irq, + chip_idx, cards_found); if (dev) { /* Get and check the latency values. On the 3c590 series @@ -722,14 +683,12 @@ u8 pci_latency; u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < new_latency) { printk(KERN_INFO "%s: Overriding PCI latency" " timer (CFLT) setting of %d, new value is %d.\n", dev->name, pci_latency, new_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, new_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency); } dev = 0; cards_found++; @@ -752,27 +711,33 @@ device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); if ((device_id & 0xFF00) != 0x5900) continue; - vortex_probe1(0, 0, ioaddr, inw(ioaddr + 0xC88) >> 12, - 4, cards_found); + vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, + 4, cards_found); cards_found++; } } -#ifdef MODULE /* Special code to work-around the Compaq PCI BIOS32 problem. */ if (compaq_ioaddr) { - vortex_probe1(0, 0, compaq_ioaddr, compaq_irq, + vortex_probe1(NULL, compaq_ioaddr, compaq_irq, compaq_device_id, cards_found++); dev = 0; } -#endif return cards_found ? 0 : -ENODEV; } #endif /* ! Cardbus */ -static struct net_device *vortex_probe1(int pci_bus, int pci_devfn, - long ioaddr, int irq, int chip_idx, int card_idx) +/* + * vortex_probe1 - initialize one vortex board, after probing + * has located one during bus scan. + * + * NOTE: pdev==NULL is a valid condition, indicating + * non-PCI (generally EISA) bus device + */ +static struct net_device *vortex_probe1(struct pci_dev *pdev, + long ioaddr, int irq, + int chip_idx, int card_idx) { struct vortex_private *vp; int option; @@ -790,11 +755,8 @@ dev->mtu = mtu; /* Make certain the descriptor lists are aligned. */ - { - void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL); - vp = (void *)(((long)mem + 15) & ~15); - vp->priv_addr = mem; - } + vp = kmalloc(sizeof(*vp), GFP_KERNEL); + memset(vp, 0, sizeof(*vp)); dev->priv = vp; @@ -802,8 +764,18 @@ root_vortex_dev = dev; vp->chip_id = chip_idx; - vp->pci_bus = pci_bus; - vp->pci_devfn = pci_devfn; + vp->pci_bus = pdev == NULL ? 0 : pdev->bus->number; + vp->pci_devfn = pdev == NULL ? 0 : pdev->devfn; + vp->pdev = pdev; + + vp->priv_addr = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE + + 15, &vp->ring_dma); + /* Make sure rings are 16 byte aligned. */ + vp->rx_ring = (void *)(((long)vp->priv_addr + 15) & ~15); + vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); + vp->rx_ring_dma = (vp->ring_dma + 15) & ~15; + vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE; /* The lower four bits are the media type. */ if (dev->mem_start) @@ -872,8 +844,7 @@ if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) { u32 fn_st_addr; /* Cardbus function status space */ - pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2, - &fn_st_addr); + fn_st_addr = pdev == NULL ? 0 : pdev->resource[2].start; if (fn_st_addr) vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128); printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee" @@ -963,6 +934,8 @@ /* The 3c59x-specific entries in the device structure. */ dev->open = &vortex_open; dev->hard_start_xmit = &vortex_start_xmit; + dev->tx_timeout = &vortex_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; dev->stop = &vortex_close; dev->get_stats = &vortex_get_stats; dev->do_ioctl = &vortex_ioctl; @@ -1106,7 +1079,7 @@ printk(KERN_DEBUG "%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; - vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1])); + vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1)); vp->rx_ring[i].status = 0; /* Clear complete bit. */ vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); skb = dev_alloc_skb(PKT_BUF_SZ); @@ -1115,11 +1088,11 @@ break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail)); + vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ)); } /* Wrap the ring. */ - vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0])); - outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); + vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); + outl(vp->rx_ring_dma, ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ dev->hard_start_xmit = &boomerang_start_xmit; @@ -1135,9 +1108,6 @@ outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ vp->in_interrupt = 0; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ @@ -1157,6 +1127,8 @@ if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ writel(0x8000, vp->cb_fn_base + 4); + netif_start_queue(dev); + MOD_INC_USE_COUNT; return 0; @@ -1313,11 +1285,11 @@ printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name); if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0) - outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]), + outl(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) { vp->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); + netif_wake_queue(dev); } outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); @@ -1431,27 +1403,23 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start >= TX_TIMEOUT) - vortex_tx_timeout(dev); - return 1; - } + netif_stop_queue(dev); /* Put out the doubleword header... */ outl(skb->len, ioaddr + TX_FIFO); if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ - outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr); - outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); + int len = (skb->len + 3) & ~3; + outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len), ioaddr + Wn7_MasterAddr); + outw(len, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; outw(StartDMADown, ioaddr + EL3_CMD); - /* dev->tbusy will be cleared at the DMADone interrupt. */ } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); DEV_FREE_SKB(skb); if (inw(ioaddr + TxFree) > 1536) { - clear_bit(0, (void*)&dev->tbusy); + netif_wake_queue(dev); } else /* Interrupt us when the FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); @@ -1493,11 +1461,9 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start >= TX_TIMEOUT) - vortex_tx_timeout(dev); - return 1; - } else { + netif_stop_queue(dev); + + if (1) { /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; struct boom_tx_desc *prev_entry = @@ -1516,10 +1482,11 @@ } vp->tx_skbuff[entry] = skb; vp->tx_ring[entry].next = 0; - vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data)); + vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len)); vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); + /* Hmm... And some poor people try to use it on SMP machines 8) */ save_flags(flags); cli(); outw(DownStall, ioaddr + EL3_CMD); @@ -1527,20 +1494,20 @@ for (i = 600; i >= 0 ; i--) if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0) break; - prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry])); + prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)); if (inl(ioaddr + DownListPtr) == 0) { - outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr); + outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); queued_packet++; } outw(DownUnstall, ioaddr + EL3_CMD); restore_flags(flags); vp->cur_tx++; - if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) + if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { vp->tx_full = 1; - else { /* Clear previous interrupt enable. */ + } else { /* Clear previous interrupt enable. */ prev_entry->status &= cpu_to_le32(~TxIntrUploaded); - clear_bit(0, (void*)&dev->tbusy); + netif_wake_queue(dev); } dev->trans_start = jiffies; vp->stats.tx_bytes += skb->len; @@ -1558,23 +1525,6 @@ int latency, status; int work_done = max_interrupt_work; -#if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } -#else - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif - - dev->interrupt = 1; ioaddr = dev->base_addr; latency = inb(ioaddr + Timer); status = inw(ioaddr + EL3_STATUS); @@ -1598,8 +1548,7 @@ printk(KERN_DEBUG " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue(dev); } if (status & DownComplete) { @@ -1608,10 +1557,13 @@ while (vp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; if (inl(ioaddr + DownListPtr) == - virt_to_bus(&vp->tx_ring[entry])) + vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)) break; /* It still hasn't been processed. */ if (vp->tx_skbuff[entry]) { - DEV_FREE_SKB(vp->tx_skbuff[entry]); + struct sk_buff *skb = vp->tx_skbuff[entry]; + + pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len); + dev_kfree_skb_irq(vp->tx_skbuff[entry]); vp->tx_skbuff[entry] = 0; } /* vp->stats.tx_packets++; Counted below. */ @@ -1621,17 +1573,16 @@ outw(AckIntr | DownComplete, ioaddr + EL3_CMD); if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { vp->tx_full= 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue(dev); } } if (status & DMADone) { if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */ + pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3); + dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */ if (inw(ioaddr + TxFree) > 1536) { - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue(dev); } else /* Interrupt when FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); } @@ -1669,11 +1620,6 @@ printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", dev->name, status); -#if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); -#else - dev->interrupt = 0; -#endif return; } @@ -1713,12 +1659,14 @@ /* 'skb_put()' points to the start of sk_buff data area. */ if (vp->bus_master && ! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) { - outl(virt_to_bus(skb_put(skb, pkt_len)), - ioaddr + Wn7_MasterAddr); + dma_addr_t dma = pci_map_single(vp->pdev, skb_put(skb, pkt_len), + pkt_len); + outl(dma, ioaddr + Wn7_MasterAddr); outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); outw(StartDMAUp, ioaddr + EL3_CMD); while (inw(ioaddr + Wn7_MasterStatus) & 0x8000) ; + pci_unmap_single(vp->pdev, dma, pkt_len); } else { insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), (pkt_len + 3) >> 2); @@ -1779,6 +1727,7 @@ /* The packet length: up to 4.5K!. */ int pkt_len = rx_status & 0x1fff; struct sk_buff *skb; + dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr); vp->stats.rx_bytes += pkt_len; if (vortex_debug > 4) @@ -1791,23 +1740,18 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ); /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), - bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)), + vp->rx_skbuff[entry]->tail, pkt_len); rx_copy++; } else { - void *temp; /* Pass up the skbuff already on the Rx ring. */ skb = vp->rx_skbuff[entry]; vp->rx_skbuff[entry] = NULL; - temp = skb_put(skb, pkt_len); - /* Remove this checking code for final release. */ - if (bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)) != temp) - printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" - " in boomerang_rx: %p vs. %p.\n", dev->name, - bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)), - temp); + skb_put(skb, pkt_len); + pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ); rx_nocopy++; } skb->protocol = eth_type_trans(skb, dev); @@ -1836,7 +1780,7 @@ break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail)); + vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ)); vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ @@ -1852,8 +1796,7 @@ long ioaddr = dev->base_addr; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (vortex_debug > 1) { printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", @@ -1885,9 +1828,7 @@ outl(0, ioaddr + UpListPtr); for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - vp->rx_skbuff[i]->free = 1; -#endif + pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ); DEV_FREE_SKB(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } @@ -1896,7 +1837,10 @@ outl(0, ioaddr + DownListPtr); for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { - DEV_FREE_SKB(vp->tx_skbuff[i]); + struct sk_buff *skb = vp->tx_skbuff[i]; + + pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len); + DEV_FREE_SKB(skb); vp->tx_skbuff[i] = 0; } } @@ -1911,7 +1855,7 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned long flags; - if (dev->start) { + if (test_bit(LINK_STATE_START, &dev->state)) { save_flags(flags); cli(); update_stats(dev->base_addr, dev); @@ -2097,9 +2041,8 @@ return; } - -#ifdef MODULE -void cleanup_module(void) + +static void __exit vortex_cleanup_module (void) { struct net_device *next_dev; @@ -2116,13 +2059,18 @@ release_region(root_vortex_dev->base_addr, pci_tbl[vp->chip_id].io_size); kfree(root_vortex_dev); - kfree(vp->priv_addr); + pci_free_consistent(vp->pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE + + 15, vp->priv_addr, vp->ring_dma); + kfree(vp); root_vortex_dev = next_dev; } } -#endif /* MODULE */ - +module_init(vortex_init_module); +module_exit(vortex_cleanup_module); + + /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" diff -u --recursive --new-file v2.3.42/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.3.42/linux/drivers/net/8390.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/net/8390.c Wed Feb 9 20:08:09 2000 @@ -167,7 +167,8 @@ NS8390_init(dev, 1); /* Set the flag before we drop the lock, That way the IRQ arrives after its set and we get no silly warnings */ - dev->start = 1; + clear_bit(LINK_STATE_RXSEM, &dev->state); + netif_start_queue(dev); spin_unlock_irqrestore(&ei_local->page_lock, flags); ei_local->irqlock = 0; return 0; @@ -186,7 +187,7 @@ spin_lock_irqsave(&ei_local->page_lock, flags); NS8390_init(dev, 0); spin_unlock_irqrestore(&ei_local->page_lock, flags); - dev->start = 0; + netif_stop_queue(dev); return 0; } @@ -198,13 +199,11 @@ unsigned long flags; /* - * We normally shouldn't be called if dev->tbusy is set, but the - * existing code does anyway. If it has been too long since the - * last Tx, we assume the board has died and kick it. We are - * bh_atomic here. + * If it has been too long since the last Tx, we assume the + * board has died and kick it. */ - if (dev->tbusy) + if (test_bit(LINK_STATE_XOFF, &dev->state)) { /* Do timeouts, just like the 8003 driver. */ int txsr; int isr; @@ -225,7 +224,7 @@ ei_local->stat.tx_errors++; isr = inb(e8390_base+EN0_ISR); - if (dev->start == 0) + if (!test_bit(LINK_STATE_START, &dev->state)) { spin_unlock_irqrestore(&ei_local->page_lock, flags); printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name); @@ -289,16 +288,6 @@ spin_lock(&ei_local->page_lock); - if (dev->interrupt) - { - printk(KERN_WARNING "%s: Tx request while isr active.\n",dev->name); - outb_p(ENISR_ALL, e8390_base + EN0_IMR); - spin_unlock(&ei_local->page_lock); - enable_irq(dev->irq); - ei_local->stat.tx_errors++; - dev_kfree_skb(skb); - return 0; - } ei_local->irqlock = 1; send_length = ETH_ZLEN < length ? length : ETH_ZLEN; @@ -332,10 +321,10 @@ else { /* We should never get here. */ if (ei_debug) - printk(KERN_DEBUG "%s: No Tx buffers free! irq=%ld tx1=%d tx2=%d last=%d\n", - dev->name, dev->interrupt, ei_local->tx1, ei_local->tx2, ei_local->lasttx); + printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n", + dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx); ei_local->irqlock = 0; - dev->tbusy = 1; + netif_stop_queue(dev); outb_p(ENISR_ALL, e8390_base + EN0_IMR); spin_unlock(&ei_local->page_lock); enable_irq(dev->irq); @@ -368,7 +357,10 @@ } else ei_local->txqueue++; - dev->tbusy = (ei_local->tx1 && ei_local->tx2); + if (ei_local->tx1 && ei_local->tx2) + netif_stop_queue(dev); + else + netif_start_queue(dev); #else /* EI_PINGPONG */ @@ -382,7 +374,7 @@ ei_local->txing = 1; NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); dev->trans_start = jiffies; - dev->tbusy = 1; + netif_stop_queue(dev); #endif /* EI_PINGPONG */ @@ -424,7 +416,7 @@ spin_lock(&ei_local->page_lock); - if (dev->interrupt || ei_local->irqlock) + if (ei_local->irqlock) { #if 1 /* This might just be an interrupt for a PCI device sharing this line */ /* The "irqlock" check is only for testing. */ @@ -438,8 +430,7 @@ return; } - - dev->interrupt = 1; + set_bit(LINK_STATE_RXSEM, &dev->state); /* Change to page 0 and read the intr status reg. */ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD); @@ -451,7 +442,7 @@ while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 && ++nr_serviced < MAX_SERVICE) { - if (dev->start == 0) + if (!test_bit(LINK_STATE_START, &dev->state)) { printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name); interrupts = 0; @@ -500,7 +491,7 @@ outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */ } } - dev->interrupt = 0; + clear_bit(LINK_STATE_RXSEM, &dev->state); spin_unlock(&ei_local->page_lock); return; } @@ -576,7 +567,7 @@ printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n", ei_local->name, ei_local->lasttx, ei_local->tx1); ei_local->tx1 = 0; - dev->tbusy = 0; + netif_start_queue(dev); if (ei_local->tx2 > 0) { ei_local->txing = 1; @@ -593,7 +584,7 @@ printk("%s: bogus last_tx_buffer %d, tx2=%d.\n", ei_local->name, ei_local->lasttx, ei_local->tx2); ei_local->tx2 = 0; - dev->tbusy = 0; + netif_start_queue(dev); if (ei_local->tx1 > 0) { ei_local->txing = 1; @@ -613,7 +604,7 @@ * Single Tx buffer: mark it free so another packet can be loaded. */ ei_local->txing = 0; - dev->tbusy = 0; + netif_start_queue(dev); #endif /* Minimize Tx latency: update the statistics after we restart TXing. */ @@ -638,7 +629,7 @@ if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++; } - mark_bh (NET_BH); + netif_wake_queue(dev); } /* We have a good packet(s), get it/them out of the buffers. @@ -849,7 +840,7 @@ unsigned long flags; /* If the card is stopped, just return the present stats. */ - if (dev->start == 0) + if (!test_bit(LINK_STATE_START, &dev->state)) return &ei_local->stat; spin_lock_irqsave(&ei_local->page_lock,flags); @@ -945,7 +936,7 @@ * Ultra32 EISA) appears to have this bug fixed. */ - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD); for(i = 0; i < 8; i++) @@ -1064,8 +1055,7 @@ outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); - dev->tbusy = 0; - dev->interrupt = 0; + netif_start_queue(dev); ei_local->tx1 = ei_local->tx2 = 0; ei_local->txing = 0; diff -u --recursive --new-file v2.3.42/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.42/linux/drivers/net/Config.in Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/Config.in Thu Feb 10 12:28:01 2000 @@ -33,6 +33,7 @@ if [ "$CONFIG_PPC" = "y" ]; then tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC + tristate ' GMAC (G4/iBook ethernet) support' CONFIG_GMAC tristate ' Symbios 53c885 (Synergy ethernet) support' CONFIG_NCR885E tristate ' National DP83902AV (Oak ethernet) support' CONFIG_OAKNET fi @@ -126,7 +127,7 @@ tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT tristate ' CS89x0 support' CONFIG_CS89x0 tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 - tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP + tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS tristate ' EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -u --recursive --new-file v2.3.42/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.42/linux/drivers/net/Makefile Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/Makefile Thu Feb 10 12:24:54 2000 @@ -20,8 +20,6 @@ ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin arcnet O_TARGET := net.o -O_OBJS := -M_OBJS := MOD_LIST_NAME := NET_MODULES # All of the (potential) objects that export symbols. @@ -48,15 +46,6 @@ endif endif -ifeq ($(CONFIG_SK98LIN),y) -SUB_DIRS += sk98lin -obj-y += sk98lin/sk98lin.o -else - ifeq ($(CONFIG_SK98LIN),m) - MOD_IN_SUB_DIRS += sk98lin - endif -endif - ifeq ($(CONFIG_TR),y) SUB_DIRS += tokenring MOD_IN_SUB_DIRS += tokenring @@ -105,7 +94,55 @@ endif endif +# +# link order important here +# +obj-$(CONFIG_PLIP) += plip.o + +obj-$(CONFIG_ROADRUNNER) += rrunner.o + +obj-$(CONFIG_HAPPYMEAL) += sunhme.o +obj-$(CONFIG_SUNLANCE) += sunlance.o +obj-$(CONFIG_SUNQE) += sunqe.o +obj-$(CONFIG_SUNBMAC) += sunbmac.o +obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o + +obj-$(CONFIG_MACE) += mace.o +obj-$(CONFIG_BMAC) += bmac.o +obj-$(CONFIG_GMAC) += gmac.o +obj-$(CONFIG_NCR885E) += ncr885e.o + +obj-$(CONFIG_OAKNET) += oaknet.o 8390.o + +obj-$(CONFIG_DGRS) += dgrs.o +obj-$(CONFIG_RCPCI) += rcpci.o +obj-$(CONFIG_VORTEX) += 3c59x.o +obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o +obj-$(CONFIG_PCNET32) += pcnet32.o +obj-$(CONFIG_EEXPRESS_PRO100) += eepro100.o +obj-$(CONFIG_TLAN) += tlan.o +obj-$(CONFIG_TULIP) += tulip.o +obj-$(CONFIG_EPIC100) += epic100.o +obj-$(CONFIG_SIS900) += sis900.o +obj-$(CONFIG_DM9102) += dmfe.o +obj-$(CONFIG_YELLOWFIN) += yellowfin.o +obj-$(CONFIG_ACENIC) += acenic.o + +ifeq ($(CONFIG_SK98LIN),y) +SUB_DIRS += sk98lin +obj-y += sk98lin/sk98lin.o +else + ifeq ($(CONFIG_SK98LIN),m) + MOD_IN_SUB_DIRS += sk98lin + endif +endif + +obj-$(CONFIG_VIA_RHINE) += via-rhine.o +obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o +# +# end link order section +# obj-$(CONFIG_AIRONET4500) += aironet4500_core.o obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o @@ -126,7 +163,6 @@ obj-$(CONFIG_ARM_ETHERH) += 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o obj-$(CONFIG_EL2) += 3c503.o 8390.o -obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_NE2000) += ne.o 8390.o obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o obj-$(CONFIG_HPLAN) += hp.o 8390.o @@ -138,7 +174,6 @@ obj-$(CONFIG_ES3210) += es3210.o 8390.o obj-$(CONFIG_LNE390) += lne390.o 8390.o obj-$(CONFIG_NE3210) += ne3210.o 8390.o -obj-$(CONFIG_PLIP) += plip.o # bsd_comp.o is *always* a module, for some documented reason # (licensing). @@ -180,14 +215,8 @@ obj-$(CONFIG_AT1500) += lance.o obj-$(CONFIG_LANCE) += lance.o obj-$(CONFIG_SUN3LANCE) += sun3lance.o -obj-$(CONFIG_PCNET32) += pcnet32.o obj-$(CONFIG_DEFXX) += defxx.o -obj-$(CONFIG_SUNLANCE) += sunlance.o obj-$(CONFIG_SGISEEQ) += sgiseeq.o -obj-$(CONFIG_HAPPYMEAL) += sunhme.o -obj-$(CONFIG_SUNQE) += sunqe.o -obj-$(CONFIG_SUNBMAC) += sunbmac.o -obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o obj-$(CONFIG_AT1700) += at1700.o obj-$(CONFIG_FMV18X) += fmv18x.o obj-$(CONFIG_EL1) += 3c501.o @@ -197,19 +226,11 @@ obj-$(CONFIG_ELMC_II) += 3c527.o obj-$(CONFIG_EL3) += 3c509.o obj-$(CONFIG_3C515) += 3c515.o -obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_EEXPRESS) += eexpress.o obj-$(CONFIG_EEXPRESS_PRO) += eepro.o -obj-$(CONFIG_EEXPRESS_PRO100) += eepro100.o obj-$(CONFIG_RTL8139) += rtl8139.o -obj-$(CONFIG_SIS900) += sis900.o -obj-$(CONFIG_DM9102) += dmfe.o -obj-$(CONFIG_YELLOWFIN) += yellowfin.o -obj-$(CONFIG_ACENIC) += acenic.o obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o -obj-$(CONFIG_TLAN) += tlan.o -obj-$(CONFIG_VIA_RHINE) += via-rhine.o obj-$(CONFIG_ZNET) += znet.o obj-$(CONFIG_DEPCA) += depca.o obj-$(CONFIG_EWRK3) += ewrk3.o @@ -223,9 +244,7 @@ obj-$(CONFIG_APRICOT) += 82596.o obj-$(CONFIG_MVME16x_NET) += 82596.o obj-$(CONFIG_BVME6000_NET) += 82596.o -obj-$(CONFIG_DEC_ELCP) += tulip.o obj-$(CONFIG_ETH16I) += eth16i.o -obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_ARIADNE2) += ariadne2.o 8390.o obj-$(CONFIG_HPLANCE) += hplance.o 7990.o obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o @@ -239,26 +258,18 @@ obj-$(CONFIG_A2065) += a2065.o obj-$(CONFIG_HYDRA) += hydra.o obj-$(CONFIG_ARIADNE) += ariadne.o -obj-$(CONFIG_DGRS) += dgrs.o obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_LTPC) += ltpc.o obj-$(CONFIG_COPS) += cops.o obj-$(CONFIG_IPDDP) += ipddp.o -obj-$(CONFIG_RCPCI) += rcpci.o -obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_MACSONIC) += macsonic.o obj-$(CONFIG_MACMACE) += macmace.o obj-$(CONFIG_MAC89x0) += mac89x0.o -obj-$(CONFIG_BMAC) += bmac.o -obj-$(CONFIG_NCR885E) += ncr885e.o -obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o -obj-$(CONFIG_OAKNET) += oaknet.o 8390.o # # HIPPI adapters # -obj-$(CONFIG_ROADRUNNER) += rrunner.o # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. diff -u --recursive --new-file v2.3.42/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.3.42/linux/drivers/net/Space.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/Space.c Mon Feb 7 09:53:20 2000 @@ -92,7 +92,6 @@ extern int apne_probe(struct net_device *); extern int bionet_probe(struct net_device *); extern int pamsnet_probe(struct net_device *); -extern int tlan_probe(struct net_device *); extern int cs89x0_probe(struct net_device *dev); extern int ethertap_probe(struct net_device *dev); extern int ether1_probe (struct net_device *dev); @@ -168,9 +167,6 @@ struct devprobe eisa_probes[] __initdata = { #ifdef CONFIG_DE4X5 /* DEC DE425, DE434, DE435 adapters */ {de4x5_probe, 0}, -#endif -#ifdef CONFIG_TLAN - {tlan_probe, 0}, #endif #ifdef CONFIG_ULTRA32 {ultra32_probe, 0}, diff -u --recursive --new-file v2.3.42/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c --- v2.3.42/linux/drivers/net/ac3200.c Mon Nov 1 13:56:26 1999 +++ linux/drivers/net/ac3200.c Thu Feb 10 12:22:03 2000 @@ -326,9 +326,6 @@ static int ac_close_card(struct net_device *dev) { - dev->start = 0; - dev->tbusy = 1; - if (ei_debug > 1) printk("%s: Shutting down ethercard.\n", dev->name); diff -u --recursive --new-file v2.3.42/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.3.42/linux/drivers/net/acenic.c Thu Nov 11 20:11:39 1999 +++ linux/drivers/net/acenic.c Thu Feb 10 12:22:03 2000 @@ -20,11 +20,13 @@ * Additional work by Pete Wyckoff for initial * Alpha and trace dump support. The trace dump support has not been * integrated yet however. + * + * Big-endian+Sparc fixes and conversion to new PCI dma mapping + * infrastructure by David S. Miller . */ #include #include -#include #include #include #include @@ -83,10 +85,6 @@ #define wmb() mb() #endif -#if (LINUX_VERSION_CODE < 0x02030e) -#define net_device device -#endif - #include "acenic.h" /* @@ -294,8 +292,103 @@ static int probed __initdata = 0; +void ace_free_descriptors(struct net_device *dev) +{ + struct ace_private *ap = dev->priv; + int size; + + if (ap->rx_std_ring != NULL) { + size = (sizeof(struct rx_desc) * + (RX_STD_RING_ENTRIES + + RX_JUMBO_RING_ENTRIES + + RX_MINI_RING_ENTRIES + + RX_RETURN_RING_ENTRIES)); + pci_free_consistent(ap->pdev, size, + ap->rx_std_ring, + ap->rx_ring_base_dma); + ap->rx_std_ring = NULL; + ap->rx_jumbo_ring = NULL; + ap->rx_mini_ring = NULL; + ap->rx_return_ring = NULL; + } + if (ap->evt_ring != NULL) { + size = (sizeof(struct event) * EVT_RING_ENTRIES); + pci_free_consistent(ap->pdev, size, + ap->evt_ring, + ap->evt_ring_dma); + ap->evt_ring = NULL; + } + if (ap->evt_prd != NULL) { + pci_free_consistent(ap->pdev, sizeof(u32), + (void *)ap->evt_prd, ap->evt_prd_dma); + ap->evt_prd = NULL; + } + if (ap->rx_ret_prd != NULL) { + pci_free_consistent(ap->pdev, sizeof(u32), + (void *)ap->rx_ret_prd, ap->rx_ret_prd_dma); + ap->rx_ret_prd = NULL; + } + if (ap->tx_csm != NULL) { + pci_free_consistent(ap->pdev, sizeof(u32), + (void *)ap->tx_csm, ap->tx_csm_dma); + ap->tx_csm = NULL; + } +} + +int ace_allocate_descriptors(struct net_device *dev) +{ + struct ace_private *ap = dev->priv; + int size; + + size = (sizeof(struct rx_desc) * + (RX_STD_RING_ENTRIES + + RX_JUMBO_RING_ENTRIES + + RX_MINI_RING_ENTRIES + + RX_RETURN_RING_ENTRIES)); + + ap->rx_std_ring = pci_alloc_consistent(ap->pdev, size, + &ap->rx_ring_base_dma); + if (ap->rx_std_ring == NULL) + goto fail; + + ap->rx_jumbo_ring = ap->rx_std_ring + RX_STD_RING_ENTRIES; + ap->rx_mini_ring = ap->rx_jumbo_ring + RX_JUMBO_RING_ENTRIES; + ap->rx_return_ring = ap->rx_mini_ring + RX_MINI_RING_ENTRIES; + + size = (sizeof(struct event) * EVT_RING_ENTRIES); + + ap->evt_ring = pci_alloc_consistent(ap->pdev, size, + &ap->evt_ring_dma); + + if (ap->evt_ring == NULL) + goto fail; + + ap->evt_prd = pci_alloc_consistent(ap->pdev, sizeof(u32), + &ap->evt_prd_dma); + if (ap->evt_prd == NULL) + goto fail; + + ap->rx_ret_prd = pci_alloc_consistent(ap->pdev, sizeof(u32), + &ap->rx_ret_prd_dma); + if (ap->rx_ret_prd == NULL) + goto fail; + + ap->tx_csm = pci_alloc_consistent(ap->pdev, sizeof(u32), + &ap->tx_csm_dma); + if (ap->tx_csm == NULL) + goto fail; + + return 0; + +fail: + /* Clean up. */ + ace_free_descriptors(dev); + iounmap(ap->regs); + unregister_netdev(dev); + return 1; +} -int __init acenic_probe(void) +static int __init acenic_probe(void) { int boards_found = 0; int version_disp; @@ -380,16 +473,16 @@ pci_set_master(pdev); +#ifdef __sparc__ + /* NOTE: Cache line size is in 32-bit word units. */ + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); +#endif /* * Remap the regs into kernel space - this is abuse of * dev->base_addr since it was means for I/O port * addresses but who gives a damn. */ -#if (LINUX_VERSION_CODE < 0x02030d) - dev->base_addr = pdev->base_address[0]; -#else dev->base_addr = pdev->resource[0].start; -#endif ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000); if (!ap->regs){ @@ -442,6 +535,9 @@ } #endif + if (ace_allocate_descriptors(dev)) + continue; + #ifdef MODULE if (ace_init(dev, boards_found)) continue; @@ -470,8 +566,6 @@ } -#ifdef MODULE -#if LINUX_VERSION_CODE > 0x20118 MODULE_AUTHOR("Jes Sorensen "); MODULE_DESCRIPTION("AceNIC/3C985 Gigabit Ethernet driver"); MODULE_PARM(link, "1-" __MODULE_STRING(8) "i"); @@ -480,10 +574,9 @@ MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); -#endif -int init_module(void) +static int __init acenic_init_module (void) { int cards; @@ -494,7 +587,7 @@ } -void cleanup_module(void) +static void __exit acenic_cleanup_module (void) { struct ace_private *ap; struct ace_regs *regs; @@ -528,26 +621,46 @@ synchronize_irq(); for (i = 0; i < RX_STD_RING_ENTRIES; i++) { - if (ap->skb->rx_std_skbuff[i]) { + struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb; + + if (skb) { + dma_addr_t mapping; + + mapping = ap->skb->rx_std_skbuff[i].mapping; + ap->rx_std_ring[i].size = 0; - set_aceaddr_bus(&ap->rx_std_ring[i].addr, 0); - dev_kfree_skb(ap->skb->rx_std_skbuff[i]); + set_aceaddr(&ap->rx_std_ring[i].addr, 0); + pci_unmap_single(ap->pdev, mapping, + ACE_STD_BUFSIZE - (2 + 16)); + dev_kfree_skb(skb); + ap->skb->rx_std_skbuff[i].skb = NULL; } } if (ap->version >= 2) { for (i = 0; i < RX_MINI_RING_ENTRIES; i++) { - if (ap->skb->rx_mini_skbuff[i]) { + struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb; + + if (skb) { + dma_addr_t mapping; + + mapping = ap->skb->rx_mini_skbuff[i].mapping; + ap->rx_mini_ring[i].size = 0; - set_aceaddr_bus(&ap->rx_mini_ring[i].addr, 0); - dev_kfree_skb(ap->skb->rx_mini_skbuff[i]); + set_aceaddr(&ap->rx_mini_ring[i].addr, 0); + pci_unmap_single(ap->pdev, mapping, + ACE_MINI_BUFSIZE - (2 + 16)); + dev_kfree_skb(skb); } } } + ace_free_descriptors(root_dev); + iounmap(regs); if(ap->trace_buf) kfree(ap->trace_buf); - kfree(ap->info); + pci_free_consistent(ap->pdev, sizeof(struct ace_info), + ap->info, ap->info_dma); kfree(ap->skb); free_irq(root_dev->irq, root_dev); unregister_netdev(root_dev); @@ -556,7 +669,9 @@ root_dev = next; } } -#endif + +module_init(acenic_init_module); +module_exit(acenic_cleanup_module); /* @@ -590,14 +705,8 @@ /* * Don't access any other registes before this point! */ -#ifdef __BIG_ENDIAN - writel(((BYTE_SWAP | WORD_SWAP | CLR_INT) | - ((BYTE_SWAP | WORD_SWAP | CLR_INT) << 24)), - ®s->HostCtrl); -#else writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)), ®s->HostCtrl); -#endif mb(); /* @@ -640,12 +749,8 @@ * value a second time works as well. This is what caused the * `Firmware not running' problem on the Tigon II. */ -#ifdef __LITTLE_ENDIAN writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL | ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, ®s->ModeStat); -#else -#error "this driver doesn't run on big-endian machines yet!" -#endif mac1 = 0; for(i = 0; i < 4; i++){ @@ -731,19 +836,23 @@ * and the control blocks for the transmit and receive rings * as they need to be setup once and for all. */ - if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL))) - return -EAGAIN; + info = pci_alloc_consistent(ap->pdev, sizeof(struct ace_info), + &ap->info_dma); + if (info == NULL) + goto fail; /* * Get the memory for the skb rings. */ if (!(ap->skb = kmalloc(sizeof(struct ace_skb), GFP_KERNEL))) - return -EAGAIN; + goto fail; + + memset(ap->skb, 0, sizeof(struct ace_skb)); if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - return -EAGAIN; + goto fail; } /* @@ -754,13 +863,11 @@ root_dev = dev; ap->info = info; - memset(info, 0, sizeof(struct ace_info)); - memset(ap->skb, 0, sizeof(struct ace_skb)); ace_load_firmware(dev); ap->fw_running = 0; - tmp_ptr = virt_to_bus((void *)info); + tmp_ptr = (unsigned long) ap->info_dma; #if (BITS_PER_LONG == 64) writel(tmp_ptr >> 32, ®s->InfoPtrHi); #else @@ -770,15 +877,15 @@ memset(ap->evt_ring, 0, EVT_RING_ENTRIES * sizeof(struct event)); - set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring); + set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring_dma); info->evt_ctrl.flags = 0; - set_aceaddr(&info->evt_prd_ptr, &ap->evt_prd); - ap->evt_prd = 0; + set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma); + *(ap->evt_prd) = 0; wmb(); writel(0, ®s->EvtCsm); - set_aceaddr_bus(&info->cmd_ctrl.rngptr, (void *)0x100); + set_aceaddr(&info->cmd_ctrl.rngptr, 0x100); info->cmd_ctrl.flags = 0; info->cmd_ctrl.max_len = 0; @@ -788,30 +895,35 @@ writel(0, ®s->CmdPrd); writel(0, ®s->CmdCsm); - set_aceaddr(&info->stats2_ptr, &info->s.stats); - - set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_std_ring); - info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4; - info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + tmp_ptr = ap->info_dma; + tmp_ptr += (unsigned long) &(((struct ace_info *)0)->s.stats); + set_aceaddr(&info->stats2_ptr, (dma_addr_t) tmp_ptr); + + set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma); + info->rx_std_ctrl.max_len = cpu_to_le16(ACE_STD_MTU + ETH_HLEN + 4); + info->rx_std_ctrl.flags = cpu_to_le16(RCB_FLG_TCP_UDP_SUM); memset(ap->rx_std_ring, 0, RX_STD_RING_ENTRIES * sizeof(struct rx_desc)); for (i = 0; i < RX_STD_RING_ENTRIES; i++) - ap->rx_std_ring[i].flags = BD_FLG_TCP_UDP_SUM; + ap->rx_std_ring[i].flags = cpu_to_le16(BD_FLG_TCP_UDP_SUM); ap->rx_std_skbprd = 0; atomic_set(&ap->cur_rx_bufs, 0); - set_aceaddr(&info->rx_jumbo_ctrl.rngptr, ap->rx_jumbo_ring); + set_aceaddr(&info->rx_jumbo_ctrl.rngptr, + (ap->rx_ring_base_dma + + (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES))); info->rx_jumbo_ctrl.max_len = 0; - info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + info->rx_jumbo_ctrl.flags = cpu_to_le16(RCB_FLG_TCP_UDP_SUM); memset(ap->rx_jumbo_ring, 0, RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc)); for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) - ap->rx_jumbo_ring[i].flags = BD_FLG_TCP_UDP_SUM | BD_FLG_JUMBO; + ap->rx_jumbo_ring[i].flags = + cpu_to_le16(BD_FLG_TCP_UDP_SUM | BD_FLG_JUMBO); ap->rx_jumbo_skbprd = 0; atomic_set(&ap->cur_jumbo_bufs, 0); @@ -820,30 +932,40 @@ RX_MINI_RING_ENTRIES * sizeof(struct rx_desc)); if (ap->version >= 2) { - set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring); - info->rx_mini_ctrl.max_len = ACE_MINI_SIZE; - info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM; + set_aceaddr(&info->rx_mini_ctrl.rngptr, + (ap->rx_ring_base_dma + + (sizeof(struct rx_desc) * + (RX_STD_RING_ENTRIES + + RX_JUMBO_RING_ENTRIES)))); + info->rx_mini_ctrl.max_len = cpu_to_le16(ACE_MINI_SIZE); + info->rx_mini_ctrl.flags = cpu_to_le16(RCB_FLG_TCP_UDP_SUM); for (i = 0; i < RX_MINI_RING_ENTRIES; i++) ap->rx_mini_ring[i].flags = - BD_FLG_TCP_UDP_SUM | BD_FLG_MINI; + cpu_to_le16(BD_FLG_TCP_UDP_SUM | BD_FLG_MINI); } else { set_aceaddr(&info->rx_mini_ctrl.rngptr, 0); - info->rx_mini_ctrl.flags = RCB_FLG_RNG_DISABLE; + info->rx_mini_ctrl.flags = cpu_to_le16(RCB_FLG_RNG_DISABLE); info->rx_mini_ctrl.max_len = 0; } ap->rx_mini_skbprd = 0; atomic_set(&ap->cur_mini_bufs, 0); - set_aceaddr(&info->rx_return_ctrl.rngptr, ap->rx_return_ring); + set_aceaddr(&info->rx_return_ctrl.rngptr, + (ap->rx_ring_base_dma + + (sizeof(struct rx_desc) * + (RX_STD_RING_ENTRIES + + RX_JUMBO_RING_ENTRIES + + RX_MINI_RING_ENTRIES)))); info->rx_return_ctrl.flags = 0; - info->rx_return_ctrl.max_len = RX_RETURN_RING_ENTRIES; + info->rx_return_ctrl.max_len = cpu_to_le16(RX_RETURN_RING_ENTRIES); memset(ap->rx_return_ring, 0, RX_RETURN_RING_ENTRIES * sizeof(struct rx_desc)); - set_aceaddr(&info->rx_ret_prd_ptr, &ap->rx_ret_prd); + set_aceaddr(&info->rx_ret_prd_ptr, ap->rx_ret_prd_dma); + *(ap->rx_ret_prd) = 0; writel(TX_RING_BASE, ®s->WinBase); ap->tx_ring = (struct tx_desc *)regs->Window; @@ -851,15 +973,15 @@ writel(0, (unsigned long)ap->tx_ring + i * 4); } - set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE); - info->tx_ctrl.max_len = TX_RING_ENTRIES; + set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE); + info->tx_ctrl.max_len = cpu_to_le16(TX_RING_ENTRIES); #if TX_COAL_INTS_ONLY - info->tx_ctrl.flags = RCB_FLG_COAL_INT_ONLY; + info->tx_ctrl.flags = cpu_to_le16(RCB_FLG_COAL_INT_ONLY); #else info->tx_ctrl.flags = 0; #endif - set_aceaddr(&info->tx_csm_ptr, &ap->tx_csm); + set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma); /* * Potential item for tuning parameter @@ -975,7 +1097,7 @@ */ ap->tx_full = 0; ap->cur_rx = 0; - ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0; + ap->tx_prd = *(ap->tx_csm) = ap->tx_ret_csm = 0; wmb(); writel(0, ®s->TxPrd); @@ -1015,6 +1137,17 @@ "the RX mini ring\n", dev->name); } return 0; + +fail: + if (info != NULL) + pci_free_consistent(ap->pdev, sizeof(struct ace_info), + info, ap->info_dma); + if (ap->skb != NULL) { + kfree(ap->skb); + ap->skb = NULL; + } + + return -EAGAIN; } @@ -1032,7 +1165,7 @@ * seconds and there is data in the transmit queue, thus we * asume the card is stuck. */ - if (ap->tx_csm != ap->tx_ret_csm){ + if (le32_to_cpu(*(ap->tx_csm)) != ap->tx_ret_csm){ printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n", dev->name, (unsigned int)readl(®s->HostCtrl)); } @@ -1112,18 +1245,22 @@ for (i = 0; i < nr_bufs; i++) { struct sk_buff *skb; struct rx_desc *rd; + dma_addr_t mapping; skb = alloc_skb(ACE_STD_BUFSIZE, GFP_ATOMIC); /* * Make sure IP header starts on a fresh cache line. */ skb_reserve(skb, 2 + 16); - ap->skb->rx_std_skbuff[idx] = skb; + mapping = pci_map_single(ap->pdev, skb->data, + ACE_STD_BUFSIZE - (2 + 16)); + ap->skb->rx_std_skbuff[idx].skb = skb; + ap->skb->rx_std_skbuff[idx].mapping = mapping; rd = &ap->rx_std_ring[idx]; - set_aceaddr(&rd->addr, skb->data); - rd->size = ACE_STD_MTU + ETH_HLEN + 4; - rd->idx = idx; + set_aceaddr(&rd->addr, mapping); + rd->size = cpu_to_le16(ACE_STD_MTU + ETH_HLEN + 4); + rd->idx = cpu_to_le16(idx); idx = (idx + 1) % RX_STD_RING_ENTRIES; } @@ -1157,18 +1294,22 @@ for (i = 0; i < nr_bufs; i++) { struct sk_buff *skb; struct rx_desc *rd; + dma_addr_t mapping; skb = alloc_skb(ACE_MINI_BUFSIZE, GFP_ATOMIC); /* * Make sure the IP header ends up on a fresh cache line */ skb_reserve(skb, 2 + 16); - ap->skb->rx_mini_skbuff[idx] = skb; + mapping = pci_map_single(ap->pdev, skb->data, + ACE_MINI_BUFSIZE - (2 + 16)); + ap->skb->rx_mini_skbuff[idx].skb = skb; + ap->skb->rx_mini_skbuff[idx].mapping = mapping; rd = &ap->rx_mini_ring[idx]; - set_aceaddr(&rd->addr, skb->data); - rd->size = ACE_MINI_SIZE; - rd->idx = idx; + set_aceaddr(&rd->addr, mapping); + rd->size = cpu_to_le16(ACE_MINI_SIZE); + rd->idx = cpu_to_le16(idx); idx = (idx + 1) % RX_MINI_RING_ENTRIES; } @@ -1200,18 +1341,22 @@ for (i = 0; i < nr_bufs; i++) { struct sk_buff *skb; struct rx_desc *rd; + dma_addr_t mapping; skb = alloc_skb(ACE_JUMBO_BUFSIZE, GFP_ATOMIC); /* * Make sure the IP header ends up on a fresh cache line */ skb_reserve(skb, 2 + 16); - ap->skb->rx_jumbo_skbuff[idx] = skb; + mapping = pci_map_single(ap->pdev, skb->data, + ACE_JUMBO_BUFSIZE - (2 + 16)); + ap->skb->rx_jumbo_skbuff[idx].skb = skb; + ap->skb->rx_jumbo_skbuff[idx].mapping = mapping; rd = &ap->rx_jumbo_ring[idx]; - set_aceaddr(&rd->addr, skb->data); - rd->size = ACE_JUMBO_MTU + ETH_HLEN + 4; - rd->idx = idx; + set_aceaddr(&rd->addr, mapping); + rd->size = cpu_to_le16(ACE_JUMBO_MTU + ETH_HLEN + 4); + rd->idx = cpu_to_le16(idx); idx = (idx + 1) % RX_JUMBO_RING_ENTRIES; } @@ -1254,10 +1399,20 @@ ace_issue_cmd(regs, &cmd); for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) { - if (ap->skb->rx_jumbo_skbuff[i]) { + struct sk_buff *skb; + + skb = ap->skb->rx_jumbo_skbuff[i].skb; + if (skb) { + dma_addr_t mapping; + + mapping = ap->skb->rx_jumbo_skbuff[i].mapping; + ap->rx_jumbo_ring[i].size = 0; - set_aceaddr_bus(&ap->rx_jumbo_ring[i].addr, 0); - dev_kfree_skb(ap->skb->rx_jumbo_skbuff[i]); + set_aceaddr(&ap->rx_jumbo_ring[i].addr, 0); + pci_unmap_single(ap->pdev, mapping, + ACE_JUMBO_BUFSIZE - (2 + 16)); + dev_kfree_skb(skb); + ap->skb->rx_jumbo_skbuff[i].skb = NULL; } } }else @@ -1280,7 +1435,11 @@ ap = (struct ace_private *)dev->priv; while (evtcsm != evtprd){ - switch (ap->evt_ring[evtcsm].evt){ + struct event evt_local; + + memcpy(&evt_local, &ap->evt_ring[evtcsm], sizeof(evt_local)); + evt_local.u.word = le32_to_cpu(evt_local.u.word); + switch (evt_local.u.data.evt){ case E_FW_RUNNING: printk(KERN_INFO "%s: Firmware up and running\n", dev->name); @@ -1290,7 +1449,7 @@ break; case E_LNK_STATE: { - u16 code = ap->evt_ring[evtcsm].code; + u16 code = evt_local.u.data.code; if (code == E_C_LINK_UP){ printk(KERN_WARNING "%s: Optical link UP\n", dev->name); @@ -1304,7 +1463,7 @@ break; } case E_ERROR: - switch(ap->evt_ring[evtcsm].code){ + switch(evt_local.u.data.code){ case E_C_ERR_INVAL_CMD: printk(KERN_ERR "%s: invalid command error\n", dev->name); @@ -1319,14 +1478,14 @@ break; default: printk(KERN_ERR "%s: unknown error %02x\n", - dev->name, ap->evt_ring[evtcsm].code); + dev->name, evt_local.u.data.code); } break; case E_RESET_JUMBO_RNG: break; default: printk(KERN_ERR "%s: Unhandled event 0x%02x\n", - dev->name, ap->evt_ring[evtcsm].evt); + dev->name, evt_local.u.data.evt); } evtcsm = (evtcsm + 1) % EVT_RING_ENTRIES; } @@ -1344,14 +1503,16 @@ idx = rxretcsm; while (idx != rxretprd){ - struct sk_buff *skb, **oldskb_p; + struct ring_info *rip; + struct sk_buff *skb; struct rx_desc *rxdesc; + dma_addr_t mapping; u32 skbidx; - int desc_type; + int desc_type, mapsize; u16 csum; - skbidx = ap->rx_return_ring[idx].idx; - desc_type = ap->rx_return_ring[idx].flags & + skbidx = le16_to_cpu(ap->rx_return_ring[idx].idx); + desc_type = le16_to_cpu(ap->rx_return_ring[idx].flags) & (BD_FLG_JUMBO | BD_FLG_MINI); switch(desc_type) { @@ -1363,42 +1524,47 @@ * atomic operations for each packet arriving. */ case 0: - oldskb_p = &ap->skb->rx_std_skbuff[skbidx]; + rip = &ap->skb->rx_std_skbuff[skbidx]; + mapsize = ACE_STD_BUFSIZE - (2 + 16); rxdesc = &ap->rx_std_ring[skbidx]; std_count++; break; case BD_FLG_JUMBO: - oldskb_p = &ap->skb->rx_jumbo_skbuff[skbidx]; + rip = &ap->skb->rx_jumbo_skbuff[skbidx]; + mapsize = ACE_JUMBO_BUFSIZE - (2 + 16); rxdesc = &ap->rx_jumbo_ring[skbidx]; atomic_dec(&ap->cur_jumbo_bufs); break; case BD_FLG_MINI: - oldskb_p = &ap->skb->rx_mini_skbuff[skbidx]; + rip = &ap->skb->rx_mini_skbuff[skbidx]; + mapsize = ACE_MINI_BUFSIZE - (2 + 16); rxdesc = &ap->rx_mini_ring[skbidx]; mini_count++; break; default: printk(KERN_INFO "%s: unknown frame type (0x%02x) " "returned by NIC\n", dev->name, - ap->rx_return_ring[idx].flags); + le16_to_cpu(ap->rx_return_ring[idx].flags)); goto error; } - skb = *oldskb_p; + skb = rip->skb; + mapping = rip->mapping; #if DEBUG if (skb == NULL) { printk("Mayday! illegal skb received! (idx %i)\n", skbidx); goto error; } #endif - *oldskb_p = NULL; - skb_put(skb, rxdesc->size); + rip->skb = NULL; + pci_unmap_single(ap->pdev, mapping, mapsize); + skb_put(skb, le16_to_cpu(rxdesc->size)); rxdesc->size = 0; /* * Fly baby, fly! */ - csum = ap->rx_return_ring[idx].tcp_udp_csum; + csum = le16_to_cpu(ap->rx_return_ring[idx].tcp_udp_csum); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); @@ -1476,22 +1642,30 @@ * working on the other stuff - hey we don't need a spin lock * anymore. */ - rxretprd = ap->rx_ret_prd; + rxretprd = le32_to_cpu(*(ap->rx_ret_prd)); rxretcsm = ap->cur_rx; if (rxretprd != rxretcsm) ace_rx_int(dev, rxretprd, rxretcsm); - txcsm = ap->tx_csm; + txcsm = le32_to_cpu(*(ap->tx_csm)); idx = ap->tx_ret_csm; if (txcsm != idx) { do { + struct sk_buff *skb; + dma_addr_t mapping; + + skb = ap->skb->tx_skbuff[idx].skb; + mapping = ap->skb->tx_skbuff[idx].mapping; + ap->stats.tx_packets++; - ap->stats.tx_bytes += ap->skb->tx_skbuff[idx]->len; - dev_kfree_skb(ap->skb->tx_skbuff[idx]); + ap->stats.tx_bytes += skb->len; + + pci_unmap_single(ap->pdev, mapping, skb->len); + dev_kfree_skb(skb); - ap->skb->tx_skbuff[idx] = NULL; + ap->skb->tx_skbuff[idx].skb = NULL; /* * Question here is whether one should not skip @@ -1514,14 +1688,14 @@ * Ie. skip the comparison of the tx producer vs. the * consumer. */ - if (ap->tx_full && dev->tbusy) { + if (ap->tx_full && + test_bit(LINK_STATE_XOFF, &dev->state)) { ap->tx_full = 0; /* * This does not need to be atomic (and expensive), * I've seen cases where it would fail otherwise ;-( */ - clear_bit(0, &dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue(dev); /* * TX ring is no longer full, aka the @@ -1535,7 +1709,7 @@ } evtcsm = readl(®s->EvtCsm); - evtprd = ap->evt_prd; + evtprd = le32_to_cpu(*(ap->evt_prd)); if (evtcsm != evtprd) { evtcsm = ace_handle_event(dev, evtcsm, evtprd); @@ -1546,7 +1720,7 @@ * This has to go last in the interrupt handler and run with * the spin lock released ... what lock? */ - if (dev->start) { + if (test_bit(LINK_STATE_START, &dev->state)) { int cur_size; int run_bh = 0; @@ -1651,10 +1825,6 @@ ace_issue_cmd(regs, &cmd); #endif - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - MOD_INC_USE_COUNT; /* @@ -1684,8 +1854,7 @@ unsigned long flags; short i; - dev->start = 0; - set_bit(0, &dev->tbusy); + netif_stop_queue(dev); ap = (struct ace_private *)dev->priv; regs = ap->regs; @@ -1713,11 +1882,17 @@ cli(); for (i = 0; i < TX_RING_ENTRIES; i++) { - if (ap->skb->tx_skbuff[i]) { + struct sk_buff *skb; + dma_addr_t mapping; + + skb = ap->skb->tx_skbuff[i].skb; + mapping = ap->skb->tx_skbuff[i].mapping; + if (skb) { writel(0, &ap->tx_ring[i].addr.addrhi); writel(0, &ap->tx_ring[i].addr.addrlo); writel(0, &ap->tx_ring[i].flagsize); - dev_kfree_skb(ap->skb->tx_skbuff[i]); + pci_unmap_single(ap->pdev, mapping, skb->len); + dev_kfree_skb(skb); } } @@ -1738,9 +1913,6 @@ unsigned long addr; u32 idx, flagsize; - if (test_and_set_bit(0, &dev->tbusy)) - return 1; - idx = ap->tx_prd; if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm) { @@ -1752,8 +1924,10 @@ return 1; } - ap->skb->tx_skbuff[idx] = skb; - addr = virt_to_bus(skb->data); + ap->skb->tx_skbuff[idx].skb = skb; + ap->skb->tx_skbuff[idx].mapping = + pci_map_single(ap->pdev, skb->data, skb->len); + addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping; #if (BITS_PER_LONG == 64) writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi); #endif @@ -1784,7 +1958,7 @@ /* * No need for it to be atomic - seems it needs to be */ - clear_bit(0, &dev->tbusy); + netif_stop_queue(dev); } dev->trans_start = jiffies; @@ -1956,7 +2130,7 @@ u16 *da; struct cmd cmd; - if(dev->start) + if(test_bit(LINK_STATE_START, &dev->state)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); @@ -2038,11 +2212,11 @@ } -void __init ace_copy(struct ace_regs *regs, void *src, u32 dest, int size) +void __init ace_copy(struct ace_regs *regs, void *src, unsigned long dest, int size) { unsigned long tdest; u32 *wsrc; - short tsize, i; + unsigned long tsize, i; if (size <= 0) return; @@ -2053,14 +2227,10 @@ tdest = (unsigned long)®s->Window + (dest & (ACE_WINDOW_SIZE - 1)); writel(dest & ~(ACE_WINDOW_SIZE - 1), ®s->WinBase); -#ifdef __BIG_ENDIAN -#error "data must be swapped here" -#else wsrc = src; for (i = 0; i < (tsize / 4); i++){ writel(wsrc[i], tdest + i*4); } -#endif dest += tsize; src += tsize; size -= tsize; @@ -2070,10 +2240,10 @@ } -void __init ace_clear(struct ace_regs *regs, u32 dest, int size) +void __init ace_clear(struct ace_regs *regs, unsigned long dest, int size) { unsigned long tdest; - short tsize = 0, i; + unsigned long tsize = 0, i; if (size <= 0) return; diff -u --recursive --new-file v2.3.42/linux/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.3.42/linux/drivers/net/acenic.h Tue Sep 7 12:14:06 1999 +++ linux/drivers/net/acenic.h Tue Feb 8 18:58:25 2000 @@ -24,60 +24,19 @@ } aceaddr; -static inline void set_aceaddr(aceaddr *aa, volatile void *addr) +static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr) { - unsigned long baddr = virt_to_bus((void *)addr); + unsigned long baddr = (unsigned long) addr; #if (BITS_PER_LONG == 64) - aa->addrlo = baddr & 0xffffffff; - aa->addrhi = baddr >> 32; + aa->addrlo = cpu_to_le32(baddr & 0xffffffff); + aa->addrhi = cpu_to_le32(baddr >> 32); #else /* Don't bother setting zero every time */ - aa->addrlo = baddr; + aa->addrlo = cpu_to_le32(baddr); #endif mb(); } - -static inline void set_aceaddr_bus(aceaddr *aa, volatile void *addr) -{ - unsigned long baddr = (unsigned long)addr; -#if (BITS_PER_LONG == 64) - aa->addrlo = baddr & 0xffffffff; - aa->addrhi = baddr >> 32; -#else - /* Don't bother setting zero every time */ - aa->addrlo = baddr; -#endif - mb(); -} - - -static inline void *get_aceaddr(aceaddr *aa) -{ - unsigned long addr; - mb(); -#if (BITS_PER_LONG == 64) - addr = (u64)aa->addrhi << 32 | aa->addrlo; -#else - addr = aa->addrlo; -#endif - return bus_to_virt(addr); -} - - -static inline void *get_aceaddr_bus(aceaddr *aa) -{ - unsigned long addr; - mb(); -#if (BITS_PER_LONG == 64) - addr = (u64)aa->addrhi << 32 | aa->addrlo; -#else - addr = aa->addrlo; -#endif - return (void *)addr; -} - - struct ace_regs { u32 pad0[16]; /* PCI control registers */ @@ -341,15 +300,20 @@ #define EVT_RING_SIZE (EVT_RING_ENTRIES * sizeof(struct event)) struct event { -#ifdef __LITTLE_ENDIAN - u32 idx:12; - u32 code:12; - u32 evt:8; -#else - u32 evt:8; - u32 code:12; - u32 idx:12; + union { + u32 word; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u32 idx:12; + u32 code:12; + u32 evt:8; +#else + u32 evt:8; + u32 code:12; + u32 idx:12; #endif + } data; + } u; u32 pad; }; @@ -387,7 +351,7 @@ #define CMD_RING_ENTRIES 64 struct cmd { -#ifdef __LITTLE_ENDIAN +#if defined(__LITTLE_ENDIAN_BITFIELD) u32 idx:12; u32 code:12; u32 evt:8; @@ -471,17 +435,10 @@ * This is in PCI shared mem and must be accessed with readl/writel * real layout is: */ -#if __LITTLE_ENDIAN u16 flags; u16 size; u16 vlan; u16 reserved; -#else - u16 size; - u16 flags; - u16 reserved; - u16 vlan; -#endif #endif u32 vlanres; }; @@ -502,34 +459,14 @@ struct rx_desc{ aceaddr addr; -#ifdef __LITTLE_ENDIAN u16 size; u16 idx; -#else - u16 idx; - u16 size; -#endif -#ifdef __LITTLE_ENDIAN u16 flags; u16 type; -#else - u16 type; - u16 flags; -#endif -#ifdef __LITTLE_ENDIAN u16 tcp_udp_csum; u16 ip_csum; -#else - u16 ip_csum; - u16 tcp_udp_csum; -#endif -#ifdef __LITTLE_ENDIAN u16 vlan; u16 err_flags; -#else - u16 err_flags; - u16 vlan; -#endif u32 reserved; u32 opague; }; @@ -540,13 +477,8 @@ */ struct ring_ctrl { aceaddr rngptr; -#ifdef __LITTLE_ENDIAN u16 flags; u16 max_len; -#else - u16 max_len; - u16 flags; -#endif u32 pad; }; @@ -608,12 +540,17 @@ * pointers, but I don't see any other smart mode to do this in an * efficient manner ;-( */ +struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + struct ace_skb { - struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; - struct sk_buff *rx_std_skbuff[RX_STD_RING_ENTRIES]; - struct sk_buff *rx_mini_skbuff[RX_MINI_RING_ENTRIES]; - struct sk_buff *rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES]; + struct ring_info tx_skbuff[TX_RING_ENTRIES]; + struct ring_info rx_std_skbuff[RX_STD_RING_ENTRIES]; + struct ring_info rx_mini_skbuff[RX_MINI_RING_ENTRIES]; + struct ring_info rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES]; }; @@ -631,12 +568,14 @@ { struct ace_skb *skb; struct ace_regs *regs; /* register base */ - int version, fw_running, fw_up, link; + volatile int fw_running; + int version, fw_up, link; int promisc, mcast_all; /* * The send ring is located in the shared memory window */ struct ace_info *info; + dma_addr_t info_dma; struct tx_desc *tx_ring; u32 tx_prd, tx_full, tx_ret_csm; struct timer_list timer; @@ -651,18 +590,22 @@ u32 cur_rx; struct tq_struct immediate; int bh_pending, jumbo; - struct rx_desc rx_std_ring[RX_STD_RING_ENTRIES] - __attribute__ ((aligned (L1_CACHE_BYTES))); - struct rx_desc rx_jumbo_ring[RX_JUMBO_RING_ENTRIES]; - struct rx_desc rx_mini_ring[RX_MINI_RING_ENTRIES]; - struct rx_desc rx_return_ring[RX_RETURN_RING_ENTRIES]; - struct event evt_ring[EVT_RING_ENTRIES]; - volatile u32 evt_prd - __attribute__ ((aligned (L1_CACHE_BYTES))); - volatile u32 rx_ret_prd - __attribute__ ((aligned (L1_CACHE_BYTES))); - volatile u32 tx_csm - __attribute__ ((aligned (L1_CACHE_BYTES))); + + /* These elements are allocated using consistent PCI + * dma memory. + */ + struct rx_desc *rx_std_ring; + struct rx_desc *rx_jumbo_ring; + struct rx_desc *rx_mini_ring; + struct rx_desc *rx_return_ring; + dma_addr_t rx_ring_base_dma; + + struct event *evt_ring; + dma_addr_t evt_ring_dma; + + volatile u32 *evt_prd, *rx_ret_prd, *tx_csm; + dma_addr_t evt_prd_dma, rx_ret_prd_dma, tx_csm_dma; + unsigned char *trace_buf; struct pci_dev *pdev; struct net_device *next; diff -u --recursive --new-file v2.3.42/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.3.42/linux/drivers/net/bmac.c Tue Nov 23 22:42:20 1999 +++ linux/drivers/net/bmac.c Thu Feb 10 12:22:03 2000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -1256,7 +1257,7 @@ return 1; } -int bmac_probe(void) +static int __init bmac_probe (void) { int j, rev; struct bmac_data *bp; @@ -1265,6 +1266,11 @@ static struct device_node *all_bmacs = NULL, *next_bmac; struct net_device *dev = NULL; +#ifdef MODULE + if(bmac_devs != NULL) + return -EBUSY; +#endif + if (all_bmacs == NULL) { all_bmacs = find_devices("bmac"); is_bmac_plus = 0; @@ -1593,23 +1599,14 @@ return len; } -#ifdef MODULE MODULE_AUTHOR("Randy Gobbel/Paul Mackerras"); MODULE_DESCRIPTION("PowerMac BMAC ethernet driver."); -int init_module(void) -{ - int res; - - if(bmac_devs != NULL) - return -EBUSY; - res = bmac_probe(); - return res; -} -void cleanup_module(void) +static void __exit bmac_cleanup (void) { +#ifdef MODULE struct bmac_data *bp; if (bmac_devs == 0) @@ -1628,6 +1625,8 @@ #endif kfree(bmac_devs); bmac_devs = NULL; +#endif } -#endif +module_init(bmac_probe); +module_exit(bmac_cleanup); diff -u --recursive --new-file v2.3.42/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.3.42/linux/drivers/net/de4x5.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/net/de4x5.c Thu Feb 10 12:22:03 2000 @@ -766,8 +766,8 @@ struct de4x5_private { char adapter_name[80]; /* Adapter name */ u_long interrupt; /* Aligned ISR flag */ - struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */ - struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */ + struct de4x5_desc *rx_ring; /* RX descriptor ring */ + struct de4x5_desc *tx_ring; /* TX descriptor ring */ struct sk_buff *tx_skb[NUM_TX_DESC]; /* TX skb for freeing when sent */ struct sk_buff *rx_skb[NUM_RX_DESC]; /* RX skb's */ int rx_new, rx_old; /* RX descriptor ring pointers */ @@ -815,7 +815,6 @@ int tmp; /* Temporary global per card */ struct { void *priv; /* Original kmalloc'd mem addr */ - void *buf; /* Original kmalloc'd mem addr */ u_long lock; /* Lock the cache accesses */ s32 csr0; /* Saved Bus Mode Register */ s32 csr6; /* Saved Operating Mode Reg. */ @@ -846,6 +845,10 @@ u_char *rst; /* Pointer to Type 5 reset info */ u_char ibn; /* Infoblock number */ struct parameters params; /* Command line/ #defined params */ + struct pci_dev *pdev; /* Device cookie for DMA alloc */ + dma_addr_t dma_rings; /* DMA handle for rings */ + int dma_size; /* Size of the DMA area */ + char *rx_bufs; /* rx bufs on alpha, sparc, ... */ }; /* @@ -910,7 +913,7 @@ /* ** Private functions */ -static int de4x5_hw_init(struct net_device *dev, u_long iobase); +static int de4x5_hw_init(struct net_device *dev, u_long iobase, struct pci_dev *pdev); static int de4x5_init(struct net_device *dev); static int de4x5_sw_reset(struct net_device *dev); static int de4x5_rx(struct net_device *dev); @@ -1125,7 +1128,7 @@ } static int __init -de4x5_hw_init(struct net_device *dev, u_long iobase) +de4x5_hw_init(struct net_device *dev, u_long iobase, struct pci_dev *pdev) { struct bus_type *lp = &bus; int i, status=0; @@ -1210,6 +1213,7 @@ lp->asBitValid = TRUE; lp->timeout = -1; lp->useSROM = useSROM; + lp->pdev = pdev; memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom)); lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; de4x5_parse_params(dev); @@ -1228,7 +1232,20 @@ } lp->fdx = lp->params.fdx; sprintf(lp->adapter_name,"%s (%s)", name, dev->name); - + + lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc); +#if defined(__alpha__) || defined(__powerpc__) || defined(__sparc_v9__) || defined(DE4X5_DO_MEMCPY) + lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + ALIGN; +#endif + lp->rx_ring = pci_alloc_consistent(pdev, lp->dma_size, &lp->dma_rings); + if (lp->rx_ring == NULL) { + kfree(lp->cache.priv); + lp->cache.priv = NULL; + return -ENOMEM; + } + + lp->tx_ring = lp->rx_ring + NUM_RX_DESC; + /* ** Set up the RX descriptor ring (Intels) ** Allocate contiguous receive buffers, long word aligned (Alphas) @@ -1236,28 +1253,30 @@ #if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) for (i=0; irx_ring[i].status = 0; - lp->rx_ring[i].des1 = RX_BUFF_SZ; + lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); lp->rx_ring[i].buf = 0; lp->rx_ring[i].next = 0; lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ } #else - if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, - GFP_KERNEL)) == NULL) { - kfree(lp->cache.priv); - lp->cache.priv = NULL; - return -ENOMEM; - } + { + dma_addr_t dma_rx_bufs; + + dma_rx_bufs = lp->dma_rings + (NUM_RX_DESC + NUM_TX_DESC) + * sizeof(struct de4x5_desc); + dma_rx_bufs = (dma_rx_bufs + ALIGN) & ~ALIGN; + lp->rx_bufs = (char *)(((long)(lp->rx_ring + NUM_RX_DESC + + NUM_TX_DESC) + ALIGN) & ~ALIGN); + for (i=0; irx_ring[i].status = 0; + lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); + lp->rx_ring[i].buf = + cpu_to_le32(dma_rx_bufs+i*RX_BUFF_SZ); + lp->rx_ring[i].next = 0; + lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ + } - lp->cache.buf = tmp; - tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN); - for (i=0; irx_ring[i].status = 0; - lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); - lp->rx_ring[i].buf = cpu_to_le32(virt_to_bus(tmp+i*RX_BUFF_SZ)); - lp->rx_ring[i].next = 0; - lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ } #endif @@ -1273,10 +1292,11 @@ /* Write the end of list marker to the descriptor lists */ lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER); lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER); - + /* Tell the adapter where the TX/RX rings are located. */ - outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); - outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); + outl(lp->dma_rings, DE4X5_RRBA); + outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc), + DE4X5_TRBA); /* Initialise the IRQ mask and Enable/Disable */ lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM; @@ -1388,8 +1408,6 @@ } } - dev->tbusy = 0; - dev->start = 1; lp->interrupt = UNMASK_INTERRUPTS; dev->trans_start = jiffies; @@ -1425,7 +1443,7 @@ de4x5_init(struct net_device *dev) { /* Lock out other processes whilst setting up the hardware */ - test_and_set_bit(0, (void *)&dev->tbusy); + netif_stop_queue(dev); de4x5_sw_reset(dev); @@ -1467,8 +1485,9 @@ omr |= (OMR_SDP | OMR_SB); } lp->setup_f = PERFECT; - outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); - outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); + outl(lp->dma_rings, DE4X5_RRBA); + outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc), + DE4X5_TRBA); lp->rx_new = lp->rx_old = 0; lp->tx_new = lp->tx_old = 0; @@ -1486,7 +1505,7 @@ /* Build the setup frame depending on filtering mode */ SetMulticastFilter(dev); - load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL); + load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, (struct sk_buff *)1); outl(omr|OMR_ST, DE4X5_OMR); /* Poll for setup frame completion (adapter interrupts are disabled now) */ @@ -1520,7 +1539,7 @@ int status = 0; u_long flags = 0; - test_and_set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */ + netif_stop_queue(dev); if (lp->tx_enable == NO) { /* Cannot send for now */ return -1; } @@ -1539,14 +1558,15 @@ return -1; /* Transmit descriptor ring full or stale skb */ - if (dev->tbusy || lp->tx_skb[lp->tx_new]) { + if (test_bit(LINK_STATE_XOFF, &dev->state) || + (u_long) lp->tx_skb[lp->tx_new] > 1) { if (lp->interrupt) { de4x5_putb_cache(dev, skb); /* Requeue the buffer */ } else { de4x5_put_cache(dev, skb); } if (de4x5_debug & DEBUG_TX) { - printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO")); + printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%d\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), test_bit(LINK_STATE_XOFF, &dev->state), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO"); } } else if (skb->len > 0) { /* If we already have stuff queued locally, use that first */ @@ -1555,9 +1575,9 @@ skb = de4x5_get_cache(dev); } - while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) { + while (skb && !test_bit(LINK_STATE_XOFF, &dev->state) && (u_long) lp->tx_skb[lp->tx_new] <= 1) { spin_lock_irqsave(&lp->lock, flags); - test_and_set_bit(0, (void*)&dev->tbusy); + netif_stop_queue(dev); load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); lp->stats.tx_bytes += skb->len; outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ @@ -1566,7 +1586,7 @@ dev->trans_start = jiffies; if (TX_BUFFS_AVAIL) { - dev->tbusy = 0; /* Another pkt may be queued */ + netif_start_queue(dev); /* Another pkt may be queued */ } skb = de4x5_get_cache(dev); spin_unlock_irqrestore(&lp->lock, flags); @@ -1643,7 +1663,7 @@ /* Load the TX ring with any locally stored packets */ if (!test_and_set_bit(0, (void *)&lp->cache.lock)) { - while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { + while (lp->cache.skb && !test_bit(LINK_STATE_XOFF, &dev->state) && lp->tx_enable) { de4x5_queue_pkt(de4x5_get_cache(dev), dev); } lp->cache.lock = 0; @@ -1732,6 +1752,16 @@ return 0; } +static inline void +de4x5_free_tx_buff(struct de4x5_private *lp, int entry) +{ + pci_unmap_single(lp->pdev, le32_to_cpu(lp->tx_ring[entry].buf), + le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1); + if ((u_long) lp->tx_skb[entry] > 1) + dev_kfree_skb(lp->tx_skb[entry]); + lp->tx_skb[entry] = NULL; +} + /* ** Buffer sent - check for TX buffer errors. */ @@ -1768,19 +1798,20 @@ ((status & TD_CC) >> 3)); /* Free the buffer. */ - if (lp->tx_skb[entry] != NULL) { - dev_kfree_skb(lp->tx_skb[entry]); - lp->tx_skb[entry] = NULL; - } + if (lp->tx_skb[entry] != NULL) + de4x5_free_tx_buff(lp, entry); } /* Update all the pointers */ lp->tx_old = (++lp->tx_old) % lp->txRingSize; } - if (TX_BUFFS_AVAIL && dev->tbusy) { /* Any resources available? */ - dev->tbusy = 0; /* Clear TX busy flag */ - if (lp->interrupt) mark_bh(NET_BH); + /* Any resources available? */ + if (TX_BUFFS_AVAIL && test_bit(LINK_STATE_XOFF, &dev->state)) { + if (lp->interrupt) + netif_wake_queue(dev); + else + netif_start_queue(dev); } return 0; @@ -1861,8 +1892,8 @@ s32 imr, omr; disable_ast(dev); - dev->start = 0; - dev->tbusy = 1; + + netif_stop_queue(dev); if (de4x5_debug & DEBUG_CLOSE) { printk("%s: Shutting down ethercard, status was %8.8x.\n", @@ -1946,8 +1977,9 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1); + dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1); - lp->tx_ring[lp->tx_new].buf = cpu_to_le32(virt_to_bus(buf)); + lp->tx_ring[lp->tx_new].buf = cpu_to_le32(buf_dma); lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER); lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags); lp->tx_skb[lp->tx_new] = skb; @@ -1956,8 +1988,6 @@ lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN); barrier(); - - return; } /* @@ -1979,7 +2009,7 @@ } else { SetMulticastFilter(dev); load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | - SETUP_FRAME_LEN, NULL); + SETUP_FRAME_LEN, (struct sk_buff *)1); lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ @@ -2108,7 +2138,7 @@ DevicePresent(EISA_APROM); dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { + if ((status = de4x5_hw_init(dev, iobase, NULL)) == 0) { num_de4x5s++; if (loading_module) link_modules(lastModule, dev); lastEISA = i; @@ -2228,7 +2258,7 @@ DevicePresent(DE4X5_APROM); if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { + if ((status = de4x5_hw_init(dev, iobase, pdev)) == 0) { num_de4x5s++; lastPCI = index; if (loading_module) link_modules(lastModule, dev); @@ -3265,10 +3295,10 @@ de4x5_rst_desc_ring(dev); de4x5_setup_intr(dev); lp->tx_enable = YES; - dev->tbusy = 0; spin_unlock_irqrestore(&lp->lock, flags); outl(POLL_DEMAND, DE4X5_TPD); - mark_bh(NET_BH); + + netif_wake_queue(dev); return; } @@ -3554,7 +3584,7 @@ lp->timeout = msec/100; lp->tmp = lp->tx_new; /* Remember the ring position */ - load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), NULL); + load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), (struct sk_buff *)1); lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); } @@ -3622,13 +3652,10 @@ skb_reserve(p, 2); /* Align */ if (index < lp->rx_old) { /* Wrapped buffer */ short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; - memcpy(skb_put(p,tlen), - bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),tlen); - memcpy(skb_put(p,len-tlen), - bus_to_virt(le32_to_cpu(lp->rx_ring[0].buf)), len-tlen); + memcpy(skb_put(p,tlen),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,tlen); + memcpy(skb_put(p,len-tlen),lp->rx_bufs,len-tlen); } else { /* Linear buffer */ - memcpy(skb_put(p,len), - bus_to_virt(le32_to_cpu(lp->rx_ring[lp->rx_old].buf)),len); + memcpy(skb_put(p,len),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,len); } return p; @@ -3659,10 +3686,8 @@ int i; for (i=0; itxRingSize; i++) { - if (lp->tx_skb[i]) { - dev_kfree_skb(lp->tx_skb[i]); - lp->tx_skb[i] = NULL; - } + if (lp->tx_skb[i]) + de4x5_free_tx_buff(lp, i); lp->tx_ring[i].status = 0; } @@ -3712,8 +3737,9 @@ if (lp->cache.save_cnt) { STOP_DE4X5; - outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); - outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); + outl(lp->dma_rings, DE4X5_RRBA); + outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc), + DE4X5_TRBA); lp->rx_new = lp->rx_old = 0; lp->tx_new = lp->tx_old = 0; @@ -5578,12 +5604,13 @@ } build_setup_frame(dev, PHYS_ADDR_ONLY); /* Set up the descriptor and give ownership to the card */ - while (test_and_set_bit(0, (void *)&dev->tbusy) != 0) barrier(); + while (test_and_set_bit(LINK_STATE_XOFF, &dev->state) != 0) + barrier(); load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | - SETUP_FRAME_LEN, NULL); + SETUP_FRAME_LEN, (struct sk_buff *)1); lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ - dev->tbusy = 0; /* Unlock the TX ring */ + netif_start_queue(dev); /* Unlock the TX ring */ break; case DE4X5_SET_PROM: /* Set Promiscuous Mode */ @@ -5735,7 +5762,7 @@ } tmp.addr[j++] = lp->txRingSize; - tmp.addr[j++] = dev->tbusy; + tmp.addr[j++] = test_bit(LINK_STATE_XOFF, &dev->state); ioc->len = j; if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; @@ -5780,12 +5807,13 @@ release_region(p->base_addr, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : DE4X5_EISA_TOTAL_SIZE)); - if (lp->cache.buf) { /* MAC buffers allocated? */ - kfree(lp->cache.buf); /* Free the MAC buffers */ - } if (lp->cache.priv) { /* Private area allocated? */ kfree(lp->cache.priv); /* Free the private area */ } + if (lp->rx_ring) { + pci_free_consistent(lp->pdev, lp->dma_size, lp->rx_ring, + lp->dma_rings); + } } kfree(p); } else { @@ -5816,8 +5844,9 @@ struct de4x5_private *lp = (struct de4x5_private *)p->priv; next = lp->next_module; - if (lp->cache.buf) { /* MAC buffers allocated? */ - kfree(lp->cache.buf); /* Free the MAC buffers */ + if (lp->rx_ring) { + pci_free_consistent(lp->pdev, lp->dma_size, lp->rx_ring, + lp->dma_rings); } release_region(p->base_addr, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : diff -u --recursive --new-file v2.3.42/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.3.42/linux/drivers/net/dgrs.c Thu Nov 11 20:11:39 1999 +++ linux/drivers/net/dgrs.c Thu Feb 10 12:22:03 2000 @@ -182,9 +182,7 @@ /* * Chain of device structures */ -#ifdef MODULE - static struct net_device *dgrs_root_dev = NULL; -#endif +static struct net_device *dgrs_root_dev = NULL; /* * Private per-board data structure (dev->priv) @@ -355,7 +353,7 @@ ) { int i; - ulong csr; + ulong csr = 0; DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv; if (pciaddr) @@ -717,7 +715,7 @@ printk("%s: xmit len=%d\n", devN->name, (int) skb->len); devN->trans_start = jiffies; - devN->tbusy = 0; + netif_start_queue(devN); if (priv0->rfdp->cmd & I596_RFD_EL) { /* Out of RFD's */ @@ -790,13 +788,9 @@ static int dgrs_open( struct net_device *dev ) { - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); -#ifdef MODULE MOD_INC_USE_COUNT; -#endif return (0); } @@ -806,12 +800,9 @@ */ static int dgrs_close( struct net_device *dev ) { - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif return (0); } @@ -940,10 +931,10 @@ if (dgrs_nicmode) { for (i = 0; i < priv0->nports; ++i) - priv0->devtbl[i]->tbusy = 0; + netif_wake_queue (priv0->devtbl[i]); } else - dev0->tbusy = 0; + netif_wake_queue (dev0); /* if (bd->flags & TX_QUEUED) DL_sched(bd, bdd); */ } @@ -1451,16 +1442,9 @@ return cards_found; } -/* - * Module/driver initialization points. Two ways, depending on - * whether we are a module or statically linked, ala Don Becker's - * 3c59x driver. - */ - -#ifdef MODULE /* - * Variables that can be overriden from command line + * Variables that can be overriden from module command line */ static int debug = -1; static int dma = -1; @@ -1480,8 +1464,7 @@ MODULE_PARM(ipxnet, "i"); MODULE_PARM(nicmode, "i"); -int -init_module(void) +static int __init dgrs_init_module (void) { int cards_found; int i; @@ -1531,8 +1514,7 @@ return cards_found ? 0 : -ENODEV; } -void -cleanup_module(void) +static void __exit dgrs_cleanup_module (void) { while (dgrs_root_dev) { @@ -1560,17 +1542,5 @@ } } -#else - -int __init -dgrs_probe(struct net_device *dev) -{ - int cards_found; - - cards_found = dgrs_scan(); - if (dgrs_debug && cards_found) - printk("dgrs: SW=%s FW=Build %d %s\n", - version, dgrs_firmnum, dgrs_firmdate); - return cards_found ? 0 : -ENODEV; -} -#endif +module_init(dgrs_init_module); +module_exit(dgrs_cleanup_module); diff -u --recursive --new-file v2.3.42/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c --- v2.3.42/linux/drivers/net/dmfe.c Thu Nov 18 20:25:37 1999 +++ linux/drivers/net/dmfe.c Thu Feb 10 12:22:03 2000 @@ -275,7 +275,7 @@ }; /* function declaration ------------------------------------- */ -int dmfe_reg_board(void); +static int dmfe_reg_board(void); static int dmfe_open(struct net_device *); static int dmfe_start_xmit(struct sk_buff *, struct net_device *); static int dmfe_stop(struct net_device *); @@ -309,7 +309,7 @@ * Search DM910X board, allocate space and register it */ -int __init dmfe_reg_board(void) +static int __init dmfe_reg_board(void) { u32 pci_iobase; u16 dm9102_count = 0; @@ -329,7 +329,6 @@ while ((net_dev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, net_dev))) { u32 pci_id; - u8 pci_cmd; index++; if (pci_read_config_dword(net_dev, PCI_VENDOR_ID, &pci_id) != DMFE_SUCC) @@ -341,15 +340,14 @@ pci_iobase = net_dev->resource[0].start; pci_irqline = net_dev->irq; + if (check_region(pci_iobase, DM9102_IO_SIZE)) /* IO range check */ + continue; + /* Enable Master/IO access, Disable memory access */ + pci_enable_device (net_dev); pci_set_master(net_dev); - pci_read_config_byte(net_dev, PCI_COMMAND, &pci_cmd); - pci_cmd |= PCI_COMMAND_IO; - pci_cmd &= ~PCI_COMMAND_MEMORY; - pci_write_config_byte(net_dev, PCI_COMMAND, pci_cmd); - /* Set Latency Timer 80h */ /* FIXME: setting values > 32 breaks some SiS 559x stuff. @@ -359,22 +357,17 @@ /* IO range and interrupt check */ - if (check_region(pci_iobase, DM9102_IO_SIZE)) /* IO range check */ - continue; - /* Found DM9102 card and PCI resource allocated OK */ dm9102_count++; /* Found a DM9102 card */ /* Init network device */ - dev = init_etherdev(NULL, 0); + dev = init_etherdev(NULL, sizeof(*db)); + if (dev == NULL) + continue; + + db = dev->priv; - /* Allocated board information structure */ - db = (void *) (kmalloc(sizeof(*db), GFP_KERNEL | GFP_DMA)); - if(db==NULL) - continue; /* Out of memory */ - memset(db, 0, sizeof(*db)); - dev->priv = db; /* link device and board info */ db->next_dev = dmfe_root_dev; dmfe_root_dev = dev; @@ -405,10 +398,9 @@ } -#ifdef MODULE if (!dm9102_count) printk(KERN_WARNING "dmfe: Can't find DM910X board\n"); -#endif + return dm9102_count ? 0 : -ENODEV; } @@ -1453,7 +1445,6 @@ } -#ifdef MODULE MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw"); MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver"); @@ -1467,7 +1458,7 @@ * to initilize and register. */ -int init_module(void) +static int __init dmfe_init_module(void) { DMFE_DBUG(0, "init_module() ", debug); @@ -1497,7 +1488,7 @@ * to un-register device. */ -void cleanup_module(void) +static void __exit dmfe_cleanup_module(void) { struct net_device *next_dev; @@ -1514,4 +1505,5 @@ DMFE_DBUG(0, "clean_module() exit", 0); } -#endif /* MODULE */ +module_init(dmfe_init_module); +module_exit(dmfe_cleanup_module); diff -u --recursive --new-file v2.3.42/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.3.42/linux/drivers/net/eepro.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/eepro.c Thu Feb 10 12:22:03 2000 @@ -138,18 +138,6 @@ #include #include #include - - -/* need to remove these asap */ -/* 2.1.xx compatibility macros... */ -/* */ - - -#include - -/* For linux 2.1.xx */ -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - #include #include #include @@ -160,16 +148,6 @@ /* udelay(2) */ #define compat_init_data __initdata -#else -/* for 2.x */ - -#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb), (mode) ) -#define test_and_set_bit(a,b) set_bit((a),(b)) -#define SLOW_DOWN SLOW_DOWN_IO -#define compat_init_data - -#endif - /* First, a few definitions that the brave might change. */ /* A zero-terminated list of I/O addresses to be probed. */ @@ -210,9 +188,8 @@ int version; /* a flag to indicate if this is a TX or FX version of the 82595 chip. */ int stepping; -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + spinlock_t lock; /* Serializing lock */ -#endif }; /* The station (ethernet) address prefix, used for IDing the board. */ @@ -299,6 +276,7 @@ #define ee_id_eepro10p0 0x10 /* ID for eepro/10+ */ #define ee_id_eepro10p1 0x31 +#define TX_TIMEOUT 40 /* Index to functions, as function prototypes. */ @@ -313,6 +291,7 @@ static int eepro_close(struct net_device *dev); static struct enet_statistics *eepro_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); +static void eepro_tx_timeout (struct net_device *dev); static int read_eeprom(int ioaddr, int location); static void hardware_send_packet(struct net_device *dev, void *buf, short length); @@ -710,14 +689,15 @@ return -ENOMEM; memset(dev->priv, 0, sizeof(struct eepro_local)); -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - spin_lock_init(&(((struct eepro_local *)dev->priv)->lock)); -#endif + ((struct eepro_local *)dev->priv)->lock = SPIN_LOCK_UNLOCKED; + dev->open = eepro_open; dev->stop = eepro_close; dev->hard_start_xmit = eepro_send_packet; dev->get_stats = eepro_get_stats; dev->set_multicast_list = &set_multicast_list; + dev->tx_timeout = eepro_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; /* Fill in the fields of the device structure with ethernet generic values */ @@ -969,10 +949,8 @@ lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; /* or = RCV_RAM */ lp->tx_last = 0; - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + + netif_start_queue(dev); if (net_debug > 3) printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name); @@ -983,81 +961,53 @@ return 0; } -static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) +static void eepro_tx_timeout (struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = (struct eepro_local *) dev->priv; int ioaddr = dev->base_addr; int rcv_ram = dev->mem_end; -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + /* if (net_debug > 1) */ + printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name, + "network cable problem"); + /* This is not a duplicate. One message for the console, + one for the the log file */ + printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name, + "network cable problem"); + lp->stats.tx_errors++; + + /* Try to restart the adaptor. */ + outb (SEL_RESET_CMD, ioaddr); + /* We are supposed to wait for 2 us after a SEL_RESET */ + SLOW_DOWN; + SLOW_DOWN; + + /* Do I also need to flush the transmit buffers here? YES? */ + lp->tx_start = lp->tx_end = rcv_ram; + lp->tx_last = 0; + + dev->trans_start = jiffies; + netif_start_queue (dev); + + outb (RCV_ENABLE_CMD, ioaddr); +} + + +static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct eepro_local *lp = (struct eepro_local *)dev->priv; unsigned long flags; -#endif if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_send_packet routine.\n", dev->name); - if (dev->tbusy) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 40) - return 1; - - /* if (net_debug > 1) */ - printk(KERN_ERR "%s: transmit timed out, %s?\n", dev->name, - "network cable problem"); - /* This is not a duplicate. One message for the console, - one for the the log file */ - printk(KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name, - "network cable problem"); - lp->stats.tx_errors++; - - /* Try to restart the adaptor. */ - outb(SEL_RESET_CMD, ioaddr); - /* We are supposed to wait for 2 us after a SEL_RESET */ - SLOW_DOWN; - SLOW_DOWN; - - /* Do I also need to flush the transmit buffers here? YES? */ - lp->tx_start = lp->tx_end = rcv_ram; - lp->tx_last = 0; - - dev->tbusy=0; - dev->trans_start = jiffies; - - outb(RCV_ENABLE_CMD, ioaddr); - - } - -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20155 - /* If some higher layer thinks we've missed an tx-done interrupt - we are passed NULL. Caution: dev_tint() handles the cli()/sti() - itself. */ - /* if (skb == NULL) { - dev_tint(dev); - return 0; - }*/ - /* according to A. Cox, this is obsolete since 1.0 */ -#endif - -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 spin_lock_irqsave(&lp->lock, flags); -#endif - - /* Block a timer-based transmit from overlapping. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - spin_unlock_irqrestore(&lp->lock, flags); -#endif - } else { + { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 lp->stats.tx_bytes+=skb->len; -#endif hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; @@ -1072,9 +1022,7 @@ if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name); -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 spin_unlock_irqrestore(&lp->lock, flags); -#endif return 0; } @@ -1096,21 +1044,7 @@ return; } -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 spin_lock(&lp->lock); -#endif - - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 - spin_unlock(&lp->lock); - /* FIXME : with the lock, could this ever happen ? */ -#endif - - return; - } - dev->interrupt = 1; if (net_debug > 5) printk(KERN_DEBUG "%s: entering eepro_interrupt routine.\n", dev->name); @@ -1143,14 +1077,10 @@ } while ((boguscount-- > 0) && (status & 0x06)); - dev->interrupt = 0; - if (net_debug > 5) printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name); -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 spin_unlock(&lp->lock); -#endif return; } @@ -1161,8 +1091,7 @@ int rcv_ram = dev->mem_end; short temp_reg; - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */ @@ -1402,12 +1331,6 @@ service routines. */ outb(ALL_MASK, ioaddr + INT_MASK_REG); - if (dev->interrupt == 1) { - /* Enable RX and TX interrupts */ - outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); - continue; - } - /* determine how much of the transmit buffer space is available */ if (lp->tx_end > lp->tx_start) tx_available = XMT_RAM - (lp->tx_end - lp->tx_start); @@ -1484,9 +1407,8 @@ lp->tx_last = last; lp->tx_end = end; - if (dev->tbusy) { - dev->tbusy = 0; - } + if (test_bit(LINK_STATE_XOFF, &dev->flags)) + netif_start_queue(dev); /* Enable RX and TX interrupts */ outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); @@ -1496,7 +1418,7 @@ return; } - dev->tbusy = 1; + netif_stop_queue(dev); if (net_debug > 5) printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); } @@ -1529,9 +1451,7 @@ /* Malloc up new buffer. */ struct sk_buff *skb; -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 lp->stats.rx_bytes+=rcv_size; -#endif rcv_size &= 0x3fff; skb = dev_alloc_skb(rcv_size+5); if (skb == NULL) { @@ -1622,8 +1542,7 @@ xmt_status = inw(ioaddr+IO_PORT); lp->tx_start = inw(ioaddr+IO_PORT); - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue (dev); if (xmt_status & 0x2000) lp->stats.tx_packets++; @@ -1650,8 +1569,6 @@ } } -#ifdef MODULE - #define MAX_EEPRO 8 static char devicename[MAX_EEPRO][9]; static struct net_device dev_eepro[MAX_EEPRO]; @@ -1670,13 +1587,14 @@ static int n_eepro = 0; /* For linux 2.1.xx */ -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155 + MODULE_AUTHOR("Pascal Dupuis for the 2.1 stuff (locking,...)"); MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver"); MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EEPRO) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i"); -#endif + +#ifdef MODULE int init_module(void) diff -u --recursive --new-file v2.3.42/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.3.42/linux/drivers/net/eepro100.c Thu Nov 11 20:11:40 1999 +++ linux/drivers/net/eepro100.c Thu Feb 10 12:22:03 2000 @@ -49,9 +49,7 @@ e.g. "options=16" for FD, "options=32" for 100mbps-only. */ static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -#ifdef MODULE static int debug = -1; /* The debug level */ -#endif /* A few values that may be tweaked. */ /* The ring sizes should be a power of two for efficiency. */ @@ -81,11 +79,11 @@ #include #include -#include #include #include #include #include +#include #ifdef HAS_PCI_NETIF #include "pci-netif.h" #else @@ -95,6 +93,7 @@ #endif #endif #include +#include #include #include @@ -103,7 +102,6 @@ #include #include -#if LINUX_VERSION_CODE > 0x20118 && defined(MODULE) MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver"); MODULE_PARM(debug, "i"); @@ -117,12 +115,8 @@ MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(multicast_filter_limit, "i"); -#endif #define RUN_AT(x) (jiffies + (x)) -/* Condensed bus+endian portability operations. */ -#define virt_to_le32bus(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32bus_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) #if (LINUX_VERSION_CODE < 0x20123) #define test_and_set_bit(val, addr) set_bit(val, addr) @@ -356,12 +350,15 @@ CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */ }; /* Do atomically if possible. */ -#if defined(__i386__) || defined(__alpha__) -#define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status) +#if defined(__i386__) || defined(__alpha__) || defined(__ia64__) +#define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status) #elif defined(__powerpc__) #define clear_suspend(cmd) clear_bit(6, &(cmd)->cmd_status) #else -#define clear_suspend(cmd) (cmd)->cmd_status &= cpu_to_le32(~CmdSuspend) +#if 0 +# error You are probably in trouble: clear_suspend() MUST be atomic. +#endif +# define clear_suspend(cmd) (cmd)->cmd_status &= cpu_to_le32(~CmdSuspend) #endif enum SCBCmdBits { @@ -439,11 +436,13 @@ /* Do not change the position (alignment) of the first few elements! The later elements are grouped for cache locality. */ struct speedo_private { - struct TxFD tx_ring[TX_RING_SIZE]; /* Commands (usually CmdTxPacket). */ + struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */ struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */ /* The addresses of a Tx/Rx-in-place packets/buffers. */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct sk_buff* rx_skbuff[RX_RING_SIZE]; + dma_addr_t rx_ring_dma[RX_RING_SIZE]; + dma_addr_t tx_ring_dma; struct descriptor *last_cmd; /* Last command sent. */ unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */ spinlock_t lock; /* Group with Tx control cache line. */ @@ -455,14 +454,15 @@ struct net_device *next_module; void *priv_addr; /* Unaligned address for kfree */ struct enet_statistics stats; - struct speedo_stats lstats; + struct speedo_stats *lstats; int chip_id; unsigned char pci_bus, pci_devfn, acpi_pwr; + struct pci_dev *pdev; struct timer_list timer; /* Media selection timer. */ int mc_setup_frm_len; /* The length of an allocated.. */ struct descriptor *mc_setup_frm; /* ..multicast setup frame. */ int mc_setup_busy; /* Avoid double-use of setup frame. */ - int in_interrupt; /* Word-aligned dev->interrupt */ + dma_addr_t mc_setup_dma; char rx_mode; /* Current PROMISC/ALLMULTI setting. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ @@ -474,7 +474,6 @@ unsigned short phy[2]; /* PHY media interfaces available. */ unsigned short advertising; /* Current PHY advertised caps. */ unsigned short partner; /* Link partner caps. */ - long last_reset; }; /* The parameters for a CmdConfigure operation. @@ -541,7 +540,6 @@ for (; pci_index < 8; pci_index++) { unsigned char pci_bus, pci_device_fn, pci_latency; - u32 pciaddr; long ioaddr; int irq; @@ -556,14 +554,15 @@ { struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); #ifdef USE_IO - pciaddr = pdev->resource[1].start; + ioaddr = pdev->resource[1].start; #else - pciaddr = pdev->resource[0].start; + ioaddr = pdev->resource[0].start; #endif irq = pdev->irq; } #else { + u32 pciaddr; u8 pci_irq_line; pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq_line); @@ -571,23 +570,30 @@ #ifdef USE_IO pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pciaddr); + pciaddr &= ~3UL; #else pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pciaddr); #endif + ioaddr = pciaddr; irq = pci_irq_line; } #endif /* Remove I/O space marker in bit 0. */ - if (pciaddr & 1) { - ioaddr = pciaddr & ~3UL; - if (check_region(ioaddr, 32)) - continue; - } else if ((ioaddr = (long)ioremap(pciaddr & ~0xfUL, 0x1000)) == 0) { - printk(KERN_INFO "Failed to map PCI address %#x.\n", - pciaddr); +#ifdef USE_IO + if (check_region(ioaddr, 32)) continue; +#else + { + unsigned long orig_ioaddr = ioaddr; + + if ((ioaddr = (long)ioremap(ioaddr & ~0xfUL, 0x1000)) == 0) { + printk(KERN_INFO "Failed to map PCI address %#lx.\n", + orig_ioaddr); + continue; + } } +#endif if (speedo_debug > 2) printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n", ioaddr, irq); @@ -626,17 +632,34 @@ { struct net_device *dev; struct speedo_private *sp; + struct pci_dev *pdev; + unsigned char *tx_ring; + dma_addr_t tx_ring_dma; const char *product; int i, option; u16 eeprom[0x100]; int acpi_idle_state = 0; -#ifndef MODULE + static int did_version = 0; /* Already printed version info. */ if (speedo_debug > 0 && did_version++ == 0) printk(version); -#endif + + pdev = pci_find_slot(pci_bus, pci_devfn); + + tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + + sizeof(struct speedo_stats), &tx_ring_dma); + if (!tx_ring) { + printk(KERN_ERR "Could not allocate DMA memory.\n"); + return NULL; + } dev = init_etherdev(NULL, sizeof(struct speedo_private)); + if (dev == NULL) { + pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + + sizeof(struct speedo_stats), + tx_ring, tx_ring_dma); + return NULL; + } if (dev->mem_start > 0) option = dev->mem_start; @@ -708,7 +731,7 @@ { const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"}; /* The self-test results must be paragraph aligned. */ - s32 str[6], *volatile self_test_results; + volatile s32 *self_test_results = (volatile s32 *)tx_ring; int boguscnt = 16000; /* Timeout for set-test. */ if (eeprom[3] & 0x03) printk(KERN_INFO " Receiver lock-up bug exists -- enabling" @@ -742,11 +765,10 @@ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ } - /* Perform a system self-test. */ - self_test_results = (s32*) ((((long) str) + 15) & ~0xf); + /* Perform a system self-test. Use the tx_ring consistent DMA mapping for it. */ self_test_results[0] = 0; self_test_results[1] = -1; - outl(virt_to_bus(self_test_results) | PortSelfTest, ioaddr + SCBPort); + outl(tx_ring_dma | PortSelfTest, ioaddr + SCBPort); do { udelay(10); } while (self_test_results[1] == -1 && --boguscnt >= 0); @@ -794,9 +816,13 @@ sp->pci_bus = pci_bus; sp->pci_devfn = pci_devfn; + sp->pdev = pdev; sp->chip_id = chip_idx; sp->acpi_pwr = acpi_idle_state; - + sp->tx_ring = (struct TxFD *)tx_ring; + sp->tx_ring_dma = tx_ring_dma; + sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE); + sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; if (card_idx >= 0) { if (full_duplex[card_idx] >= 0) @@ -814,6 +840,8 @@ /* The Speedo-specific entries in the device structure. */ dev->open = &speedo_open; dev->hard_start_xmit = &speedo_start_xmit; + dev->tx_timeout = &speedo_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; dev->stop = &speedo_close; dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; @@ -909,8 +937,7 @@ sp->dirty_tx = 0; sp->last_cmd = 0; sp->tx_full = 0; - sp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; - sp->in_interrupt = 0; + spin_lock_init(&sp->lock); /* .. we can safely take handler calls during init. */ if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) { @@ -943,9 +970,8 @@ /* Fire up the hardware. */ speedo_resume(dev); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + clear_bit(LINK_STATE_RXSEM, &dev->state); + netif_start_queue(dev); /* Setup the chip and configure the multicast list. */ sp->mc_setup_frm = NULL; @@ -999,12 +1025,12 @@ wait_for_cmd_done(ioaddr + SCBCmd); /* Load the statistics block and rx ring addresses. */ - outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer); + outl(sp->tx_ring_dma + sizeof(struct TxFD) * TX_RING_SIZE, ioaddr + SCBPointer); outb(CUStatsAddr, ioaddr + SCBCmd); - sp->lstats.done_marker = 0; + sp->lstats->done_marker = 0; wait_for_cmd_done(ioaddr + SCBCmd); - outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]), + outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], ioaddr + SCBPointer); outb(RxStart, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); @@ -1019,7 +1045,8 @@ /* Avoid a bug(?!) here by marking the command already completed. */ cur_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000); cur_cmd->link = - virt_to_le32bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); + cpu_to_le32(sp->tx_ring_dma + (sp->cur_tx % TX_RING_SIZE) + * sizeof(struct TxFD)); memcpy(cur_cmd->params, dev->dev_addr, 6); if (sp->last_cmd) clear_suspend(sp->last_cmd); @@ -1028,7 +1055,8 @@ /* Start the chip's Tx process and unmask interrupts. */ wait_for_cmd_done(ioaddr + SCBCmd); - outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), + outl(sp->tx_ring_dma + + (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD), ioaddr + SCBPointer); outw(CUStart, ioaddr + SCBCmd); } @@ -1065,12 +1093,6 @@ printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); } - /* This has a small false-trigger window. */ - if (test_bit(0, (void*)&dev->tbusy) && - (jiffies - dev->trans_start) > TX_TIMEOUT) { - speedo_tx_timeout(dev); - sp->last_reset = jiffies; - } if (sp->rx_mode < 0 || (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) { /* We haven't received a packet in a Long Time. We might have been @@ -1135,18 +1157,16 @@ skb->dev = dev; /* Mark as being used by this device. */ rxf = (struct RxFD *)skb->tail; sp->rx_ringp[i] = rxf; + sp->rx_ring_dma[i] = + pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD)); skb_reserve(skb, sizeof(struct RxFD)); if (last_rxf) - last_rxf->link = virt_to_le32bus(rxf); + last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); last_rxf = rxf; rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ - /* This field unused by i82557, we use it as a consistency check. */ -#ifdef final_version + /* This field unused by i82557. */ rxf->rx_buf_addr = 0xffffffff; -#else - rxf->rx_buf_addr = virt_to_bus(skb->tail); -#endif rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -1175,7 +1195,8 @@ /* Only the command unit has stopped. */ printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", dev->name); - outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), + outl(sp->tx_ring_dma + + (sp->dirty_tx % TX_RING_SIZE) * sizeof(struct TxFD), ioaddr + SCBPointer); outw(CUStart, ioaddr + SCBCmd); } else { @@ -1209,22 +1230,6 @@ long ioaddr = dev->base_addr; int entry; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - If this ever occurs the queue layer is doing something evil! */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < TX_TIMEOUT - 2) - return 1; - if (tickssofar < TX_TIMEOUT) { - /* Reap sent packets from the full Tx queue. */ - outw(SCBTriggerIntr, ioaddr + SCBCmd); - return 1; - } - speedo_tx_timeout(dev); - return 1; - } - /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -1240,12 +1245,18 @@ sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex); sp->tx_ring[entry].link = - virt_to_le32bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); + cpu_to_le32(sp->tx_ring_dma + + (sp->cur_tx % TX_RING_SIZE) + * sizeof(struct TxFD)); sp->tx_ring[entry].tx_desc_addr = - virt_to_le32bus(&sp->tx_ring[entry].tx_buf_addr0); + cpu_to_le32(sp->tx_ring_dma + + ((long)&sp->tx_ring[entry].tx_buf_addr0 + - (long)sp->tx_ring)); /* The data region is always in one buffer descriptor. */ sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold); - sp->tx_ring[entry].tx_buf_addr0 = virt_to_le32bus(skb->data); + sp->tx_ring[entry].tx_buf_addr0 = + cpu_to_le32(pci_map_single(sp->pdev, skb->data, + skb->len)); sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len); /* Todo: perhaps leave the interrupt bit set if the Tx queue is more than half full. Argument against: we should be receiving packets @@ -1255,12 +1266,12 @@ { struct descriptor *last_cmd = sp->last_cmd; sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - clear_suspend(last_cmd); + last_cmd->cmd_status &= cpu_to_le32(~(CmdSuspend | CmdIntr)); } - if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) + if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) { sp->tx_full = 1; - else - clear_bit(0, (void*)&dev->tbusy); + netif_stop_queue(dev); + } spin_unlock_irqrestore(&sp->lock, flags); } wait_for_cmd_done(ioaddr + SCBCmd); @@ -1288,16 +1299,6 @@ ioaddr = dev->base_addr; sp = (struct speedo_private *)dev->priv; -#ifndef final_version - /* A lock to prevent simultaneous entry on SMP machines. */ - if (test_and_set_bit(0, (void*)&sp->in_interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - sp->in_interrupt = 0; /* Avoid halting machine. */ - return; - } - dev->interrupt = 1; -#endif do { status = inw(ioaddr + SCBStatus); @@ -1319,7 +1320,7 @@ outw(RxResumeNoResources, ioaddr + SCBCmd); else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */ /* No idea of what went wrong. Restart the receiver. */ - outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]), + outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], ioaddr + SCBPointer); outw(RxStart, ioaddr + SCBCmd); } @@ -1350,10 +1351,18 @@ #if LINUX_VERSION_CODE > 0x20127 sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; #endif - dev_free_skb(sp->tx_skbuff[entry]); + pci_unmap_single(sp->pdev, + le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0), + sp->tx_skbuff[entry]->len); + dev_kfree_skb_irq(sp->tx_skbuff[entry]); sp->tx_skbuff[entry] = 0; - } else if ((status & 0x70000) == CmdNOp) + } else if ((status & 0x70000) == CmdNOp) { + if (sp->mc_setup_busy) + pci_unmap_single(sp->pdev, + sp->mc_setup_dma, + sp->mc_setup_frm_len); sp->mc_setup_busy = 0; + } dirty_tx++; } @@ -1371,7 +1380,6 @@ && sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) { /* The ring is no longer full, clear tbusy. */ sp->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); spin_unlock(&sp->lock); netif_wake_queue(dev); } else @@ -1391,8 +1399,6 @@ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); - dev->interrupt = 0; - clear_bit(0, (void*)&sp->in_interrupt); return; } @@ -1436,6 +1442,8 @@ skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ + pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], + PKT_BUF_SZ + sizeof(struct RxFD)); #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -1455,15 +1463,9 @@ } sp->rx_skbuff[entry] = NULL; temp = skb_put(skb, pkt_len); -#if !defined(final_version) && !defined(__powerpc__) - if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) - printk(KERN_ERR "%s: Rx consistency error -- the skbuff " - "addresses do not match in speedo_rx: %p vs. %p " - "/ %p.\n", dev->name, - bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), - skb->head, temp); -#endif sp->rx_ringp[entry] = NULL; + pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry], + PKT_BUF_SZ + sizeof(struct RxFD)); } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); @@ -1489,16 +1491,19 @@ break; /* Better luck next time! */ } rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail; + sp->rx_ring_dma[entry] = + pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + + sizeof(struct RxFD)); skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); - rxf->rx_buf_addr = virt_to_bus(skb->tail); + rxf->rx_buf_addr = 0xffffffff; } else { rxf = sp->rx_ringp[entry]; } rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */ rxf->link = 0; /* None yet. */ rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); - sp->last_rxf->link = virt_to_le32bus(rxf); + sp->last_rxf->link = cpu_to_le32(sp->rx_ring_dma[entry]); sp->last_rxf->status &= cpu_to_le32(~0xC0000000); sp->last_rxf = rxf; } @@ -1514,8 +1519,7 @@ struct speedo_private *sp = (struct speedo_private *)dev->priv; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (speedo_debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", @@ -1536,6 +1540,9 @@ sp->rx_skbuff[i] = 0; /* Clear the Rx descriptors. */ if (skb) { + pci_unmap_single(sp->pdev, + sp->rx_ring_dma[i], + PKT_BUF_SZ + sizeof(struct RxFD)); #if LINUX_VERSION_CODE < 0x20100 skb->free = 1; #endif @@ -1546,9 +1553,14 @@ for (i = 0; i < TX_RING_SIZE; i++) { struct sk_buff *skb = sp->tx_skbuff[i]; sp->tx_skbuff[i] = 0; + /* Clear the Tx descriptors. */ - if (skb) + if (skb) { + pci_unmap_single(sp->pdev, + le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), + skb->len); dev_free_skb(skb); + } } if (sp->mc_setup_frm) { kfree(sp->mc_setup_frm); @@ -1587,20 +1599,20 @@ long ioaddr = dev->base_addr; /* Update only if the previous dump finished. */ - if (sp->lstats.done_marker == le32_to_cpu(0xA007)) { - sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats.tx_coll16_errs); - sp->stats.tx_window_errors += le32_to_cpu(sp->lstats.tx_late_colls); - sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_underruns); - sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats.tx_lost_carrier); - /*sp->stats.tx_deferred += le32_to_cpu(sp->lstats.tx_deferred);*/ - sp->stats.collisions += le32_to_cpu(sp->lstats.tx_total_colls); - sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats.rx_crc_errs); - sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats.rx_align_errs); - sp->stats.rx_over_errors += le32_to_cpu(sp->lstats.rx_resource_errs); - sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats.rx_overrun_errs); - sp->stats.rx_length_errors += le32_to_cpu(sp->lstats.rx_runt_errs); - sp->lstats.done_marker = 0x0000; - if (dev->start) { + if (sp->lstats->done_marker == le32_to_cpu(0xA007)) { + sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats->tx_coll16_errs); + sp->stats.tx_window_errors += le32_to_cpu(sp->lstats->tx_late_colls); + sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_underruns); + sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_lost_carrier); + /*sp->stats.tx_deferred += le32_to_cpu(sp->lstats->tx_deferred);*/ + sp->stats.collisions += le32_to_cpu(sp->lstats->tx_total_colls); + sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats->rx_crc_errs); + sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats->rx_align_errs); + sp->stats.rx_over_errors += le32_to_cpu(sp->lstats->rx_resource_errs); + sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats->rx_overrun_errs); + sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs); + sp->lstats->done_marker = 0x0000; + if (test_bit(LINK_STATE_START, &dev->state)) { wait_for_cmd_done(ioaddr + SCBCmd); outw(CUDumpStats, ioaddr + SCBCmd); } @@ -1690,7 +1702,8 @@ sp->tx_skbuff[entry] = 0; /* Redundant. */ sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure); sp->tx_ring[entry].link = - virt_to_le32bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]); + cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE) + * sizeof(struct TxFD)); config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr; /* Construct a full CmdConfig frame. */ memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd)); @@ -1726,7 +1739,8 @@ sp->tx_skbuff[entry] = 0; sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList); sp->tx_ring[entry].link = - virt_to_le32bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]); + cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE) + * sizeof(struct TxFD)); sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */ setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr; *setup_params++ = cpu_to_le16(dev->mc_count*6); @@ -1750,12 +1764,17 @@ struct descriptor *mc_setup_frm = sp->mc_setup_frm; int i; + /* If we are busy, someone might be quickly adding to the MC list. + Try again later when the list updates stop. */ + if (sp->mc_setup_busy) { + sp->rx_mode = -1; + return; + } if (sp->mc_setup_frm_len < 10 + dev->mc_count*6 || sp->mc_setup_frm == NULL) { /* Allocate a full setup frame, 10bytes + . */ if (sp->mc_setup_frm) kfree(sp->mc_setup_frm); - sp->mc_setup_busy = 0; sp->mc_setup_frm_len = 10 + multicast_filter_limit*6; sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC); if (sp->mc_setup_frm == NULL) { @@ -1765,12 +1784,6 @@ return; } } - /* If we are busy, someone might be quickly adding to the MC list. - Try again later when the list updates stop. */ - if (sp->mc_setup_busy) { - sp->rx_mode = -1; - return; - } mc_setup_frm = sp->mc_setup_frm; /* Fill the setup frame. */ if (speedo_debug > 1) @@ -1796,16 +1809,18 @@ entry = sp->cur_tx++ % TX_RING_SIZE; last_cmd = sp->last_cmd; sp->last_cmd = mc_setup_frm; - sp->mc_setup_busy++; + sp->mc_setup_busy = 1; /* Change the command to a NoOp, pointing to the CmdMulti command. */ sp->tx_skbuff[entry] = 0; sp->tx_ring[entry].status = cpu_to_le32(CmdNOp); - sp->tx_ring[entry].link = virt_to_le32bus(mc_setup_frm); + sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len); + sp->tx_ring[entry].link = cpu_to_le32(sp->mc_setup_dma); /* Set the link in the setup frame. */ mc_setup_frm->link = - virt_to_le32bus(&(sp->tx_ring[(entry+1) % TX_RING_SIZE])); + cpu_to_le32(sp->tx_ring_dma + ((entry + 1) % TX_RING_SIZE) + * sizeof(struct TxFD)); wait_for_cmd_done(ioaddr + SCBCmd); clear_suspend(last_cmd); @@ -1819,10 +1834,9 @@ sp->rx_mode = new_rx_mode; } - -#ifdef MODULE -int init_module(void) + +static int __init eepro100_init_module(void) { int cards_found; @@ -1847,7 +1861,7 @@ return 0; } -void cleanup_module(void) +static void __exit eepro100_cleanup_module(void) { struct net_device *next_dev; @@ -1871,22 +1885,9 @@ } } -#else /* not MODULE */ +module_init(eepro100_init_module); +module_exit(eepro100_cleanup_module); -int eepro100_probe(void) -{ - int cards_found = 0; - - cards_found = eepro100_init(); - - /* Only emit the version if the driver is being used. */ - if (speedo_debug > 0 && cards_found) - printk(version); - - return cards_found ? 0 : -ENODEV; -} -#endif /* MODULE */ - /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` `[ -f ./pci-netif.h ] && echo -DHAS_PCI_NETIF`" diff -u --recursive --new-file v2.3.42/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.3.42/linux/drivers/net/epic100.c Thu Nov 11 20:11:40 1999 +++ linux/drivers/net/epic100.c Thu Feb 10 12:22:03 2000 @@ -46,17 +46,7 @@ #define TX_FIFO_THRESH 256 /* Rounded down to 4 byte units. */ #define RX_FIFO_THRESH 1 /* 0-3, 0==32, 64,96, or 3==128 bytes */ -#include /* Evil, but neccessary */ -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include #include #include @@ -65,11 +55,8 @@ #include #include #include -#if LINUX_VERSION_CODE >= 0x20155 +#include #define PCI_SUPPORT_VER2 -#else -#include -#endif #include #include /* Processor type for cache alignment. */ @@ -83,13 +70,8 @@ /* Kernel compatibility defines, common to David Hind's PCMCIA package. This is only in the support-all-kernels source code. */ -#if ! defined (LINUX_VERSION_CODE) || LINUX_VERSION_CODE < 0x20000 -#warning This driver version is only for kernel versions 2.0.0 and later. -#endif - #define RUN_AT(x) (jiffies + (x)) -#if defined(MODULE) && (LINUX_VERSION_CODE >= 0x20115) MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver"); MODULE_PARM(debug, "i"); @@ -97,19 +79,7 @@ MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); -#endif -#if LINUX_VERSION_CODE < 0x20123 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define DEV_FREE_SKB(skb) dev_kfree_skb(skb, FREE_WRITE); -#else /* Grrr, unneeded incompatible change. */ #define DEV_FREE_SKB(skb) dev_kfree_skb(skb); -#endif /* The I/O extent. */ #define EPIC_TOTAL_SIZE 0x100 @@ -151,7 +121,7 @@ /* The rest of these values should never change. */ -static struct net_device *epic_probe1(int pci_bus, int pci_devfn, long ioaddr, int irq, +static struct net_device *epic_probe1(struct pci_dev *pdev, long ioaddr, int irq, int chip_id, int card_idx); enum pci_flags_bit { @@ -163,8 +133,9 @@ const char *name; u16 vendor_id, device_id, device_id_mask, pci_flags; int io_size, min_latency; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, - long ioaddr, int irq, int chip_idx, int fnd_cnt); + struct net_device *(*probe1)(struct pci_dev *pdev, + long ioaddr, int irq, int chip_idx, + int fnd_cnt); } chip_tbl[] = { {"SMSC EPIC/100 83c170", 0x10B8, 0x0005, 0x7fff, PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1}, @@ -217,6 +188,8 @@ char devname[8]; /* Used only for kernel debugging. */ const char *product_name; struct net_device *next_module; + + spinlock_t lock; /* Tx and Rx rings here so that they remain paragraph aligned. */ struct epic_rx_desc rx_ring[RX_RING_SIZE]; @@ -273,7 +246,7 @@ static struct net_device *root_epic_dev = NULL; #ifndef CARDBUS -int epic100_probe(void) +static int __init epic100_probe(void) { int cards_found = 0; int chip_idx, irq; @@ -281,7 +254,6 @@ unsigned char pci_bus, pci_device_fn; struct net_device *dev; -#ifdef PCI_SUPPORT_VER2 struct pci_dev *pcidev = NULL; while ((pcidev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pcidev)) != NULL) { @@ -300,76 +272,33 @@ pci_bus = pcidev->bus->number; pci_device_fn = pcidev->devfn; irq = pcidev->irq; -#else - int pci_index; - - if ( ! pcibios_present()) - return -ENODEV; - - for (pci_index = 0; pci_index < 0xff; pci_index++) { - u8 pci_irq_line; - u16 vendor, device; - u32 pci_ioaddr; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, - pci_index, &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); - - for (chip_idx = 0; chip_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == chip_tbl[chip_idx].vendor_id - && (device & chip_tbl[chip_idx].device_id_mask) == - chip_tbl[chip_idx].device_id) - break; - if (chip_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; - - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - /* Remove I/O space marker in bit 0. */ - pci_ioaddr &= ~3; - irq = pci_irq_line; - - if (check_region(pci_ioaddr, chip_tbl[chip_idx].io_size)) - continue; -#endif /* EPIC-specific code: Soft-reset the chip ere setting as master. */ outl(0x0001, pci_ioaddr + GENCTL); /* Activate the card: fix for brain-damaged Win98 BIOSes. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pcidev, PCI_COMMAND, &pci_command); new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; if (pci_command != new_command) { printk(KERN_INFO " The PCI BIOS has not enabled Ethernet" " device %4.4x-%4.4x." " Updating PCI command %4.4x->%4.4x.\n", vendor, device, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); + pci_write_config_word(pcidev, PCI_COMMAND, new_command); } - dev = chip_tbl[chip_idx].probe1(pci_bus, pci_device_fn, pci_ioaddr, - irq, chip_idx, cards_found); + dev = chip_tbl[chip_idx].probe1(pcidev, pci_ioaddr, irq, + chip_idx, cards_found); /* Check the latency timer. */ if (dev) { u8 pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < chip_tbl[chip_idx].min_latency) { printk(KERN_INFO " PCI latency timer (CFLT) value of %d is " "unreasonably low, setting to %d.\n", pci_latency, chip_tbl[chip_idx].min_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, + pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, chip_tbl[chip_idx].min_latency); } dev = 0; @@ -381,8 +310,8 @@ } #endif /* not CARDBUS */ -static struct net_device *epic_probe1(int pci_bus, int pci_devfn, long ioaddr, int irq, - int chip_idx, int card_idx) +static struct net_device *epic_probe1(struct pci_dev *pdev, long ioaddr, int irq, + int chip_idx, int card_idx) { struct epic_private *ep; int i, option = 0, duplex = 0; @@ -444,13 +373,10 @@ ep->next_module = root_epic_dev; root_epic_dev = dev; - ep->pci_bus = pci_bus; - ep->pci_dev_fn = pci_devfn; -#if defined(PCI_SUPPORT_VER2) - ep->chip_id = pci_find_slot(pci_bus, pci_devfn)->device; -#else - ep->chip_id = chip_tbl[chip_idx].device_id; -#endif + ep->lock = SPIN_LOCK_UNLOCKED; + ep->pci_bus = pdev->bus->number; + ep->pci_dev_fn = pdev->devfn; + ep->chip_id = pdev->device; /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but @@ -497,6 +423,8 @@ dev->get_stats = &epic_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = epic_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; return dev; } @@ -653,9 +581,7 @@ set_rx_mode(dev); outl(0x000A, ioaddr + COMMAND); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); /* Enable interrupts by setting the interrupt mask. */ outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170) @@ -864,15 +790,6 @@ int entry; u32 flag; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - epic_tx_timeout(dev); - return 1; - } - /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -889,13 +806,13 @@ if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ flag = 0x10; /* No interrupt */ - clear_bit(0, (void*)&dev->tbusy); + netif_start_queue(dev); } else if (ep->cur_tx - ep->dirty_tx == TX_RING_SIZE/2) { flag = 0x14; /* Tx-done intr. */ - clear_bit(0, (void*)&dev->tbusy); + netif_start_queue(dev); } else if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE - 2) { flag = 0x10; /* No Tx-done intr. */ - clear_bit(0, (void*)&dev->tbusy); + netif_start_queue(dev); } else { /* Leave room for two additional entries. */ flag = 0x14; /* Tx-done intr. */ @@ -927,21 +844,7 @@ long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; -#if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_ERR "%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } -#else - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif + spin_lock (&ep->lock); do { status = inl(ioaddr + INTSTAT); @@ -1004,12 +907,12 @@ } #endif - if (ep->tx_full && dev->tbusy - && dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) { + if (ep->tx_full && + test_bit(LINK_STATE_XOFF, &dev->flags) && + dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ ep->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (dev); } ep->dirty_tx = dirty_tx; @@ -1057,12 +960,7 @@ printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, inl(ioaddr + INTSTAT)); -#if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); -#else - dev->interrupt = 0; -#endif - return; + spin_unlock (&ep->lock); } static int epic_rx(struct net_device *dev) @@ -1147,8 +1045,7 @@ struct epic_private *ep = (struct epic_private *)dev->priv; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (epic_debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", @@ -1176,9 +1073,6 @@ ep->rx_ring[i].buflength = 0; ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ if (skb) { -#if LINUX_VERSION_CODE < 0x20100 - skb->free = 1; -#endif DEV_FREE_SKB(skb); } } @@ -1202,7 +1096,7 @@ struct epic_private *ep = (struct epic_private *)dev->priv; long ioaddr = dev->base_addr; - if (dev->start) { + if (test_bit(LINK_STATE_START, &dev->state)) { /* Update the error counts. */ ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); @@ -1288,12 +1182,12 @@ data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (! dev->start) { + if (! test_bit(LINK_STATE_START, &dev->state)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); - if (! dev->start) { + if (! test_bit(LINK_STATE_START, &dev->state)) { #ifdef notdef outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); @@ -1303,12 +1197,12 @@ case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!suser()) return -EPERM; - if (! dev->start) { + if (! test_bit(LINK_STATE_START, &dev->state)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); - if (! dev->start) { + if (! test_bit(LINK_STATE_START, &dev->state)) { #ifdef notdef outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); @@ -1331,13 +1225,15 @@ u16 dev_id; u32 io; u8 bus, devfn, irq; + struct pci_dev *pdev; if (loc->bus != LOC_PCI) return NULL; - bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; + pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); + if (!pdev) return NULL; printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn); - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); - pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq); - pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); + io = pdev->resource[0].start; + irq = pdev->irq; + dev_id = pdev->device; io &= ~3; if (io == 0 || irq == 0) { printk(KERN_ERR "The EPIC/C CardBus Ethernet interface was not " @@ -1407,10 +1303,8 @@ #endif /* Cardbus support */ - -#ifdef MODULE -int init_module(void) +static int __init epic100_init_module(void) { if (epic_debug) printk(KERN_INFO "%s", version); @@ -1423,7 +1317,7 @@ #endif } -void cleanup_module(void) +static void __exit epic100_cleanup_module(void) { struct net_device *next_dev; @@ -1443,8 +1337,10 @@ } } -#endif /* MODULE */ - +module_init(epic100_init_module); +module_exit(epic100_cleanup_module); + + /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c epic100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" diff -u --recursive --new-file v2.3.42/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c --- v2.3.42/linux/drivers/net/ethertap.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/ethertap.c Wed Feb 9 20:08:09 2000 @@ -123,9 +123,7 @@ MOD_DEC_USE_COUNT; return -ENOBUFS; } - - dev->start = 1; - dev->tbusy = 0; + netif_start_queue(dev); return 0; } @@ -319,8 +317,7 @@ if (ethertap_debug > 2) printk("%s: Shutting down.\n", dev->name); - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); if (sk) { lp->nl = NULL; diff -u --recursive --new-file v2.3.42/linux/drivers/net/gmac.c linux/drivers/net/gmac.c --- v2.3.42/linux/drivers/net/gmac.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/gmac.c Thu Feb 10 12:22:03 2000 @@ -0,0 +1,612 @@ +/* + * Network device driver for the GMAC ethernet controller on + * Apple G4 Powermacs. + * + * Copyright (C) 2000 Paul Mackerras. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gmac.h" + +#define DEBUG_PHY + +#define NTX 32 /* must be power of 2 */ +#define NRX 32 /* must be power of 2 */ +#define RX_BUFLEN (ETH_FRAME_LEN + 8) + +struct gmac_dma_desc { + unsigned int cmd; + unsigned int status; + unsigned int address; /* phys addr, low 32 bits */ + unsigned int hi_addr; +}; + +/* Bits in cmd */ +#define RX_OWN 0x80000000 /* 1 = owned by chip */ +#define TX_SOP 0x80000000 +#define TX_EOP 0x40000000 + +struct gmac { + volatile unsigned int *regs; /* hardware registers, virtual addr */ + volatile unsigned int *sysregs; + unsigned long desc_page; /* page for DMA descriptors */ + volatile struct gmac_dma_desc *rxring; + struct sk_buff *rx_buff[NRX]; + int next_rx; + volatile struct gmac_dma_desc *txring; + struct sk_buff *tx_buff[NTX]; + int next_tx; + int tx_gone; + unsigned char tx_full; + int phy_addr; + int full_duplex; + struct net_device_stats stats; +}; + +#define GM_OUT(r, v) out_le32(gm->regs + (r)/4, (v)) +#define GM_IN(r) in_le32(gm->regs + (r)/4) +#define GM_BIS(r, v) GM_OUT((r), GM_IN(r) | (v)) +#define GM_BIC(r, v) GM_OUT((r), GM_IN(r) & ~(v)) + +#define PHY_B5400 0x6040 +#define PHY_B5201 0x6212 + +static unsigned char dummy_buf[RX_BUFLEN+2]; +static struct net_device *gmacs = NULL; + +/* Prototypes */ +static int mii_read(struct gmac *gm, int phy, int r); +static int mii_write(struct gmac *gm, int phy, int r, int v); +static void powerup_transceiver(struct gmac *gm); +static int gmac_reset(struct net_device *dev); +static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr); +static void gmac_init_rings(struct gmac *gm); +static void gmac_start_dma(struct gmac *gm); +static int gmac_open(struct net_device *dev); +static int gmac_close(struct net_device *dev); +static int gmac_xmit_start(struct sk_buff *skb, struct net_device *dev); +static int gmac_tx_cleanup(struct gmac *gm); +static void gmac_receive(struct net_device *dev); +static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static struct net_device_stats *gmac_stats(struct net_device *dev); +static int gmac_probe(void); + +/* Stuff for talking to the physical-layer chip */ +static int +mii_read(struct gmac *gm, int phy, int r) +{ + int timeout; + + GM_OUT(MIFFRAME, 0x60020000 | (phy << 23) | (r << 18)); + for (timeout = 1000; timeout > 0; --timeout) { + udelay(20); + if (GM_IN(MIFFRAME) & 0x10000) + return GM_IN(MIFFRAME) & 0xffff; + } + return -1; +} + +static int +mii_write(struct gmac *gm, int phy, int r, int v) +{ + int timeout; + + GM_OUT(MIFFRAME, 0x50020000 | (phy << 23) | (r << 18) | (v & 0xffff)); + for (timeout = 1000; timeout > 0; --timeout) { + udelay(20); + if (GM_IN(MIFFRAME) & 0x10000) + return 0; + } + return -1; +} + +static void +mii_poll_start(struct gmac *gm) +{ + unsigned int tmp; + + /* Start the MIF polling on the external transceiver. */ + tmp = GM_IN(MIFCONFIG); + tmp &= ~(GMAC_MIF_CFGPR_MASK | GMAC_MIF_CFGPD_MASK); + tmp |= ((gm->phy_addr & 0x1f) << GMAC_MIF_CFGPD_SHIFT); + tmp |= (0x19 << GMAC_MIF_CFGPR_SHIFT); + tmp |= GMAC_MIF_CFGPE; + GM_OUT(MIFCONFIG, tmp); + + /* Let the bits set. */ + udelay(GMAC_MIF_POLL_DELAY); + + GM_OUT(MIFINTMASK, 0xffc0); +} + +static void +mii_poll_stop(struct gmac *gm) +{ + GM_OUT(MIFINTMASK, 0xffff); + GM_BIC(MIFCONFIG, GMAC_MIF_CFGPE); + udelay(GMAC_MIF_POLL_DELAY); +} + +static void +mii_interrupt(struct gmac *gm) +{ + unsigned long flags; + int phy_status; + + save_flags(flags); + cli(); + + mii_poll_stop(gm); + + /* May the status change before polling is re-enabled ? */ + mii_poll_start(gm); + + /* We read the Auxilliary Status Summary register */ + phy_status = mii_read(gm, gm->phy_addr, 0x19); +#ifdef DEBUG_PHY + printk("mii_interrupt, phy_status: %x\n", phy_status); +#endif + /* Auto-neg. complete ? */ + if (phy_status & 0x8000) { + int full_duplex = 0; + switch((phy_status >> 8) & 0x7) { + case 2: + case 5: + full_duplex = 1; + break; + } + if (full_duplex != gm->full_duplex) { + GM_BIC(TXMAC_CONFIG, 1); + udelay(200); + if (full_duplex) { + printk("full duplex active\n"); + GM_OUT(TXMAC_CONFIG, 6); + GM_OUT(XIF_CONFIG, 1); + } else { + printk("half duplex active\n"); + GM_OUT(TXMAC_CONFIG, 0); + GM_OUT(XIF_CONFIG, 5); + } + GM_BIS(TXMAC_CONFIG, 1); + gm->full_duplex = full_duplex; + } + } + + restore_flags(flags); +} + +static void +powerup_transceiver(struct gmac *gm) +{ + int phytype = mii_read(gm, 0, 3); +#ifdef DEBUG_PHY + int i; +#endif + switch (phytype) { + case PHY_B5400: + mii_write(gm, 0, 0, mii_read(gm, 0, 0) & ~0x800); + mii_write(gm, 31, 30, mii_read(gm, 31, 30) & ~8); + break; + case PHY_B5201: + mii_write(gm, 0, 30, mii_read(gm, 0, 30) & ~8); + break; + default: + printk(KERN_ERR "GMAC: unknown PHY type %x\n", phytype); + } + /* Check this */ + gm->phy_addr = 0; + gm->full_duplex = 0; + +#ifdef DEBUG_PHY + printk("PHY regs:\n"); + for (i=0; i<0x20; i++) { + printk("%04x ", mii_read(gm, 0, i)); + if ((i % 4) == 3) + printk("\n"); + } +#endif +} + +static int +gmac_reset(struct net_device *dev) +{ + struct gmac *gm = (struct gmac *) dev->priv; + int timeout; + + /* turn on GB clock */ + out_le32(gm->sysregs + 0x20/4, in_le32(gm->sysregs + 0x20/4) | 2); + udelay(10); + GM_OUT(SW_RESET, 3); + for (timeout = 100; timeout > 0; --timeout) { + mdelay(10); + if ((GM_IN(SW_RESET) & 3) == 0) + return 0; + } + printk(KERN_ERR "GMAC: reset failed!\n"); + return -1; +} + +static void +gmac_mac_init(struct gmac *gm, unsigned char *mac_addr) +{ + int i; + + GM_OUT(RANSEED, 937); + GM_OUT(DATAPATHMODE, 4); + mii_write(gm, 0, 0, 0x1000); + GM_OUT(TXDMA_CONFIG, 0xffc00); + GM_OUT(RXDMA_CONFIG, 0); + GM_OUT(MACPAUSE, 0x1bf0); + GM_OUT(IPG0, 0); + GM_OUT(IPG1, 8); + GM_OUT(IPG2, 4); + GM_OUT(MINFRAMESIZE, 64); + GM_OUT(MAXFRAMESIZE, 2000); + GM_OUT(PASIZE, 7); + GM_OUT(JAMSIZE, 4); + GM_OUT(ATTEMPT_LIMIT, 16); + GM_OUT(SLOTTIME, 64); + GM_OUT(MACCNTL_TYPE, 0x8808); + GM_OUT(MAC_ADDR_0, (mac_addr[4] << 8) + mac_addr[5]); + GM_OUT(MAC_ADDR_1, (mac_addr[2] << 8) + mac_addr[3]); + GM_OUT(MAC_ADDR_2, (mac_addr[0] << 8) + mac_addr[1]); + GM_OUT(MAC_ADDR_3, 0); + GM_OUT(MAC_ADDR_4, 0); + GM_OUT(MAC_ADDR_5, 0); + GM_OUT(MAC_ADDR_6, 0x0180); + GM_OUT(MAC_ADDR_7, 0xc200); + GM_OUT(MAC_ADDR_8, 0x0001); + GM_OUT(MAC_ADDR_FILTER_0, 0); + GM_OUT(MAC_ADDR_FILTER_1, 0); + GM_OUT(MAC_ADDR_FILTER_2, 0); + GM_OUT(MAC_ADDR_FILTER_MASK21, 0); + GM_OUT(MAC_ADDR_FILTER_MASK0, 0); + for (i = 0; i < 27; ++i) + GM_OUT(MAC_HASHTABLE + i, 0); + GM_OUT(MACCNTL_CONFIG, 0); + /* default to half duplex */ + GM_OUT(TXMAC_CONFIG, 0); + GM_OUT(XIF_CONFIG, 5); +} + +static void +gmac_init_rings(struct gmac *gm) +{ + int i; + struct sk_buff *skb; + unsigned char *data; + struct gmac_dma_desc *ring; + + /* init rx ring */ + ring = (struct gmac_dma_desc *) gm->rxring; + memset(ring, 0, NRX * sizeof(struct gmac_dma_desc)); + for (i = 0; i < NRX; ++i, ++ring) { + data = dummy_buf; + gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2); + if (skb != 0) { + /*skb_reserve(skb, 2);*/ + data = skb->data; + } + st_le32(&ring->address, virt_to_bus(data)); + st_le32(&ring->cmd, RX_OWN); + } + + /* init tx ring */ + ring = (struct gmac_dma_desc *) gm->txring; + memset(ring, 0, NRX * sizeof(struct gmac_dma_desc)); + + /* set pointers in chip */ + mb(); + GM_OUT(RXDMA_BASE_HIGH, 0); + GM_OUT(RXDMA_BASE_LOW, virt_to_bus(gm->rxring)); + GM_OUT(TXDMA_BASE_HIGH, 0); + GM_OUT(TXDMA_BASE_LOW, virt_to_bus(gm->txring)); +} + +static void +gmac_start_dma(struct gmac *gm) +{ + GM_BIS(RXDMA_CONFIG, 1); + GM_BIS(RXMAC_CONFIG, 1); + GM_OUT(RXDMA_KICK, NRX); + GM_BIS(TXDMA_CONFIG, 1); + GM_BIS(TXMAC_CONFIG, 1); +} + +static int gmac_open(struct net_device *dev) +{ + struct gmac *gm = (struct gmac *) dev->priv; + + if (gmac_reset(dev)) + return -EIO; + + MOD_INC_USE_COUNT; + + powerup_transceiver(gm); + gmac_mac_init(gm, dev->dev_addr); + gmac_init_rings(gm); + gmac_start_dma(gm); + mii_interrupt(gm); + + GM_OUT(INTR_DISABLE, 0xfffdffe8); + + return 0; +} + +static int gmac_close(struct net_device *dev) +{ + struct gmac *gm = (struct gmac *) dev->priv; + int i; + + mii_poll_stop(gm); + + GM_BIC(RXDMA_CONFIG, 1); + GM_BIC(RXMAC_CONFIG, 1); + GM_BIC(TXDMA_CONFIG, 1); + GM_BIC(TXMAC_CONFIG, 1); + GM_OUT(INTR_DISABLE, ~0U); + for (i = 0; i < NRX; ++i) { + if (gm->rx_buff[i] != 0) { + dev_kfree_skb(gm->rx_buff[i]); + gm->rx_buff[i] = 0; + } + } + for (i = 0; i < NTX; ++i) { + if (gm->tx_buff[i] != 0) { + dev_kfree_skb(gm->tx_buff[i]); + gm->tx_buff[i] = 0; + } + } + + MOD_DEC_USE_COUNT; + return 0; +} + +static int gmac_xmit_start(struct sk_buff *skb, struct net_device *dev) +{ + struct gmac *gm = (struct gmac *) dev->priv; + volatile struct gmac_dma_desc *dp; + unsigned long flags; + int i; + + save_flags(flags); cli(); + i = gm->next_tx; + if (gm->tx_buff[i] != 0) { + /* buffer is full, can't send this packet at the moment */ + dev->tbusy = 1; + gm->tx_full = 1; + restore_flags(flags); + return 1; + } + gm->next_tx = (i + 1) & (NTX - 1); + gm->tx_buff[i] = skb; + restore_flags(flags); + + dp = &gm->txring[i]; + dp->status = 0; + dp->hi_addr = 0; + st_le32(&dp->address, virt_to_bus(skb->data)); + mb(); + st_le32(&dp->cmd, TX_SOP | TX_EOP | skb->len); + mb(); + + GM_OUT(TXDMA_KICK, gm->next_tx); + + return 0; +} + +static int gmac_tx_cleanup(struct gmac *gm) +{ + int i = gm->tx_gone; + volatile struct gmac_dma_desc *dp; + struct sk_buff *skb; + int ret = 0; + int gone = GM_IN(TXDMA_COMPLETE); + + while (i != gone) { + skb = gm->tx_buff[i]; + if (skb == NULL) + break; + dp = &gm->txring[i]; + gm->stats.tx_bytes += skb->len; + ++gm->stats.tx_packets; + gm->tx_buff[i] = NULL; + dev_kfree_skb(skb); + if (++i >= NTX) + i = 0; + } + if (i != gm->tx_gone) { + ret = gm->tx_full; + gm->tx_gone = i; + gm->tx_full = 0; + } + return ret; +} + +static void gmac_receive(struct net_device *dev) +{ + struct gmac *gm = (struct gmac *) dev->priv; + int i = gm->next_rx; + volatile struct gmac_dma_desc *dp; + struct sk_buff *skb; + int len; + unsigned char *data; + + for (;;) { + dp = &gm->rxring[i]; + if (ld_le32(&dp->cmd) & RX_OWN) + break; + len = (ld_le32(&dp->cmd) >> 16) & 0x7fff; + skb = gm->rx_buff[i]; + if (skb == 0) { + ++gm->stats.rx_dropped; + } else if (ld_le32(&dp->status) & 0x40000000) { + ++gm->stats.rx_errors; + dev_kfree_skb(skb); + } else { + skb_put(skb, len); + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + gm->stats.rx_bytes += skb->len; + ++gm->stats.rx_packets; + } + data = dummy_buf; + gm->rx_buff[i] = skb = dev_alloc_skb(RX_BUFLEN + 2); + if (skb != 0) { + /*skb_reserve(skb, 2);*/ + data = skb->data; + } + st_le32(&dp->address, virt_to_bus(data)); + dp->hi_addr = 0; + mb(); + st_le32(&dp->cmd, RX_OWN); + if (++i >= NRX) + i = 0; + } + gm->next_rx = i; +} + +static void gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gmac *gm = (struct gmac *) dev->priv; + unsigned int status; + + status = GM_IN(INTR_STATUS); + GM_OUT(INTR_ACK, status); + + if (status & GMAC_IRQ_MIF) { + mii_interrupt(gm); + } + gmac_receive(dev); + if (gmac_tx_cleanup(gm)){ + dev->tbusy = 0; + mark_bh(NET_BH); + } +} + +static struct net_device_stats *gmac_stats(struct net_device *dev) +{ + struct gmac *gm = (struct gmac *) dev->priv; + + return &gm->stats; +} + +static int __init gmac_probe(void) +{ + static int gmacs_found; + static struct device_node *next_gmac; + struct device_node *gmac; + struct gmac *gm; + unsigned long descpage; + unsigned char *addr; + int i; + + if (gmacs != NULL) + return -EBUSY; + + /* + * We could (and maybe should) do this using PCI scanning + * for vendor/net_device ID 0x106b/0x21. + */ + if (!gmacs_found) { + next_gmac = find_compatible_devices("network", "gmac"); + gmacs_found = 1; + } + if ((gmac = next_gmac) == 0) + return -ENODEV; + next_gmac = gmac->next; + + if (gmac->n_addrs < 1 || gmac->n_intrs < 1) { + printk(KERN_ERR "can't use GMAC %s: %d addrs and %d intrs\n", + gmac->full_name, gmac->n_addrs, gmac->n_intrs); + return -ENODEV; + } + + dev = init_etherdev(0, sizeof(struct gmac)); + memset(dev->priv, 0, sizeof(struct gmac)); + + gm = (struct gmac *) dev->priv; + dev->base_addr = gmac->addrs[0].address; + gm->regs = (volatile unsigned int *) + ioremap(gmac->addrs[0].address, 0x10000); + gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000); + dev->irq = gmac->intrs[0].line; + + addr = get_property(gmac, "local-mac-address", NULL); + if (addr == NULL) { + printk(KERN_ERR "Can't get mac-address for GMAC %s\n", + gmac->full_name); + return -EAGAIN; + } + + printk(KERN_INFO "%s: GMAC at", dev->name); + for (i = 0; i < 6; ++i) { + dev->dev_addr[i] = addr[i]; + printk("%c%.2x", (i? ':': ' '), addr[i]); + } + printk("\n"); + + descpage = get_free_page(GFP_KERNEL); + if (descpage == 0) { + printk(KERN_ERR "GMAC: can't get a page for descriptors\n"); + return -EAGAIN; + } + + gm->desc_page = descpage; + gm->rxring = (volatile struct gmac_dma_desc *) descpage; + gm->txring = (volatile struct gmac_dma_desc *) (descpage + 0x800); + + gm->phy_addr = 0; + + dev->open = gmac_open; + dev->stop = gmac_close; + dev->hard_start_xmit = gmac_xmit_start; + dev->get_stats = gmac_stats; + + ether_setup(dev); + + if (request_irq(dev->irq, gmac_interrupt, 0, "GMAC", dev)) { + printk(KERN_ERR "GMAC: can't get irq %d\n", dev->irq); + return -EAGAIN; + } + + gmacs = dev; + + return 0; +} + +MODULE_AUTHOR("Paul Mackerras"); +MODULE_DESCRIPTION("PowerMac GMAC driver."); + + +static void __exit gmac_cleanup_module(void) +{ + struct gmac *gm; + + /* XXX should handle more than one */ + if (gmacs == NULL) + return; + + gm = (struct gmac *) gmacs->priv; + free_irq(gmacs->irq, gmac_interrupt); + free_page(gm->descpage); + unregister_netdev(gmacs); + kfree(gmacs); + gmacs = NULL; +} + +module_init(gmac_probe); +module_exit(gmac_cleanup_module); + diff -u --recursive --new-file v2.3.42/linux/drivers/net/gmac.h linux/drivers/net/gmac.h --- v2.3.42/linux/drivers/net/gmac.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/gmac.h Wed Feb 9 19:43:53 2000 @@ -0,0 +1,113 @@ +/* + * Definitions for the GMAC ethernet chip, used in the + * Apple G4 powermac. + */ + +/* Register offsets */ +#define INTR_STATUS 0x000c +#define INTR_DISABLE 0x0010 +#define INTR_ACK 0x0014 +#define SW_RESET 0x1010 +#define TXDMA_KICK 0x2000 +#define TXDMA_CONFIG 0x2004 +#define TXDMA_BASE_LOW 0x2008 +#define TXDMA_BASE_HIGH 0x200c +#define TXDMA_STATE_MACH 0x2028 +#define TXDMA_COMPLETE 0x2100 +#define RXDMA_CONFIG 0x4000 +#define RXDMA_BASE_LOW 0x4004 +#define RXDMA_BASE_HIGH 0x4008 +#define RXDMA_KICK 0x4100 +#define MACPAUSE 0x6008 +#define TXMAC_STATUS 0x6010 +#define TXMAC_CONFIG 0x6030 +#define RXMAC_CONFIG 0x6034 +#define MACCNTL_CONFIG 0x6038 +#define XIF_CONFIG 0x603c +#define IPG0 0x6040 +#define IPG1 0x6044 +#define IPG2 0x6048 +#define SLOTTIME 0x604c +#define MINFRAMESIZE 0x6050 +#define MAXFRAMESIZE 0x6054 +#define PASIZE 0x6058 +#define JAMSIZE 0x605c +#define ATTEMPT_LIMIT 0x6060 +#define MACCNTL_TYPE 0x6064 +#define MAC_ADDR_0 0x6080 +#define MAC_ADDR_1 0x6084 +#define MAC_ADDR_2 0x6088 +#define MAC_ADDR_3 0x608c +#define MAC_ADDR_4 0x6090 +#define MAC_ADDR_5 0x6094 +#define MAC_ADDR_6 0x6098 +#define MAC_ADDR_7 0x609c +#define MAC_ADDR_8 0x60a0 +#define MAC_ADDR_FILTER_0 0x60a4 +#define MAC_ADDR_FILTER_1 0x60a8 +#define MAC_ADDR_FILTER_2 0x60ac +#define MAC_ADDR_FILTER_MASK21 0x60b0 +#define MAC_ADDR_FILTER_MASK0 0x60b4 +#define MAC_HASHTABLE 0x60c0 +#define RANSEED 0x6130 +#define MIFFRAME 0x620c +#define MIFCONFIG 0x6210 +#define MIFINTMASK 0x6214 +#define MIFSTATUS 0x6218 +#define DATAPATHMODE 0x9050 + +/* -- 0x000C R-C Global Interrupt status. + * d: 0x00000000 bits 0-6 cleared on read (C) + */ +#define GMAC_IRQ_TX_INT_ME 0x00000001 /* C Frame with INT_ME bit set in fifo */ +#define GMAC_IRQ_TX_ALL 0x00000002 /* C TX descriptor ring empty */ +#define GMAC_IRQ_TX_DONE 0x00000004 /* C moved from host to TX fifo */ +#define GMAC_IRQ_RX_DONE 0x00000010 /* C moved from RX fifo to host */ +#define GMAC_IRQ_RX_NO_BUF 0x00000020 /* C No RX buffer available */ +#define GMAC_IRQ_RX_TAG_ERR 0x00000040 /* C RX tag error */ + +#define GMAC_IRQ_PCS 0x00002000 /* PCS interrupt ? */ +#define GMAC_IRQ_MAC_TX 0x00004000 /* MAC tx register set */ +#define GMAC_IRQ_MAC_RX 0x00008000 /* MAC rx register set */ +#define GMAC_IRQ_MAC_CTRL 0x00010000 /* MAC control register set */ +#define GMAC_IRQ_MIF 0x00020000 /* MIF status register set */ +#define GMAC_IRQ_BUS_ERROR 0x00040000 /* Bus error status register set */ + +#define GMAC_IRQ_TX_COMP 0xfff80000 /* TX completion mask */ + +/* -- 0x6210 RW MIF config reg + */ + +#define GMAC_MIF_CFGPS 0x00000001 /* PHY Select */ +#define GMAC_MIF_CFGPE 0x00000002 /* Poll Enable */ +#define GMAC_MIF_CFGBB 0x00000004 /* Bit Bang Enable */ +#define GMAC_MIF_CFGPR_MASK 0x000000f8 /* Poll Register address */ +#define GMAC_MIF_CFGPR_SHIFT 3 +#define GMAC_MIF_CFGM0 0x00000100 /* MDIO_0 Data / MDIO_0 attached */ +#define GMAC_MIF_CFGM1 0x00000200 /* MDIO_1 Data / MDIO_1 attached */ +#define GMAC_MIF_CFGPD_MASK 0x00007c00 /* Poll Device PHY address */ +#define GMAC_MIF_CFGPD_SHIFT 10 + +#define GMAC_MIF_POLL_DELAY 200 + +#define GMAC_INTERNAL_PHYAD 1 /* PHY address for int. transceiver */ +#define GMAC_EXTERNAL_PHYAD 0 /* PHY address for ext. transceiver */ + + +/* -- 0x6214 RW MIF interrupt mask reg + * same as basic/status Register + */ + +/* -- 0x6214 RW MIF basic/status reg + * The Basic portion of this register indicates the last + * value of the register read indicated in the POLL REG field + * of the Configuration Register. + * The Status portion indicates bit(s) that have changed. + * The MIF Mask register is corresponding to this register in + * terms of the bit(s) that need to be masked for generating + * interrupt on the MIF Interrupt Bit of the Global Status Rgister. + */ + +#define GMAC_MIF_STATUS 0x0000ffff /* 0-15 : Status */ +#define GMAC_MIF_BASIC 0xffff0000 /* 16-31 : Basic register */ + diff -u --recursive --new-file v2.3.42/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.3.42/linux/drivers/net/hp100.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/net/hp100.c Thu Feb 10 12:24:54 2000 @@ -96,6 +96,7 @@ #include #include #include +#include #include #include @@ -177,6 +178,7 @@ struct hp100_private { struct hp100_eisa_id *id; + spinlock_t lock; u_short chip; u_short soft_model; u_int memory_size; @@ -192,7 +194,7 @@ struct pci_dev *pci_dev; #endif short mem_mapped; /* memory mapped access */ - u32 *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ + void *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ unsigned long mem_ptr_phys; /* physical memory mapped area */ short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ int hub_status; /* was login to hub successful? */ @@ -308,7 +310,7 @@ static hp100_stats_t *hp100_get_stats( struct net_device *dev ); static void hp100_misc_interrupt( struct net_device *dev ); static void hp100_update_stats( struct net_device *dev ); -static void hp100_clear_stats( int ioaddr ); +static void hp100_clear_stats( struct hp100_private *lp, int ioaddr ); static void hp100_set_multicast_list( struct net_device *dev); static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ); static void hp100_start_interface( struct net_device *dev ); @@ -533,7 +535,7 @@ u_short local_mode, lsw; short mem_mapped; unsigned long mem_ptr_phys; - u32 **mem_ptr_virt; + void **mem_ptr_virt; struct hp100_private *lp; struct hp100_eisa_id *eid; @@ -761,7 +763,7 @@ else { #ifdef HP100_DEBUG - printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", dev->name, virt_memory_size, mem_ptr_phys, (u_long)mem_ptr_virt); + printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to %p.\n", dev->name, virt_memory_size, mem_ptr_phys, mem_ptr_virt); #endif break; } @@ -792,6 +794,7 @@ lp = (struct hp100_private *)dev->priv; memset( lp, 0, sizeof( struct hp100_private ) ); + lp->lock = SPIN_LOCK_UNLOCKED; lp->id = eid; lp->chip = chip; lp->mode = local_mode; @@ -855,7 +858,7 @@ dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i ); /* Reset statistics (counters) */ - hp100_clear_stats( ioaddr ); + hp100_clear_stats( lp, ioaddr ); ether_setup( dev ); @@ -914,7 +917,7 @@ dev->name,mem_ptr_phys, (mem_ptr_phys+(mem_ptr_phys>0x100000?(u_long)lp->memory_size:16*1024))-1 ); if ( mem_ptr_virt ) - printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt ); + printk( " (virtual base %p)", mem_ptr_virt ); printk( ".\n" ); /* Set for info when doing ifconfig */ @@ -1252,10 +1255,8 @@ MOD_INC_USE_COUNT; - dev->tbusy = 0; dev->trans_start = jiffies; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); lp->lan_type = hp100_sense_lan( dev ); lp->mac1_mode = HP100_MAC1MODE3; @@ -1291,8 +1292,7 @@ if ( lp->lan_type == HP100_LAN_100 ) lp->hub_status=hp100_login_to_vg_hub( dev, FALSE ); - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); free_irq( dev->irq, dev ); @@ -1724,8 +1724,7 @@ * we have to turn int's off before modifying this, otherwise * a tx_pdl_cleanup could occur at the same time */ - save_flags( flags ); - cli(); + spin_lock_irqsave (&lp->lock, flags); ringptr=lp->txrtail; lp->txrtail=ringptr->next; @@ -1751,7 +1750,7 @@ hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */ lp->txrcommit++; - restore_flags( flags ); + spin_unlock_irqrestore (&lp->lock, flags); /* Update statistics */ lp->stats.tx_packets++; @@ -1931,9 +1930,9 @@ if ( lp->mem_ptr_virt ) /* high pci memory was remapped */ { /* Note: The J2585B needs alignment to 32bits here! */ - memcpy( lp->mem_ptr_virt, skb->data, ( skb->len + 3 ) & ~3 ); + memcpy_toio( lp->mem_ptr_virt, skb->data, ( skb->len + 3 ) & ~3 ); if ( !ok_flag ) - memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len ); + memset_io( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len ); } else { @@ -2060,7 +2059,7 @@ if ( lp->mode==2 ) { if ( lp->mem_ptr_virt ) - memcpy( ptr, lp->mem_ptr_virt, pkt_len ); + memcpy_fromio( ptr, lp->mem_ptr_virt, pkt_len ); /* Note alignment to 32bit transfers */ else isa_memcpy_fromio( ptr, lp->mem_ptr_phys, pkt_len ); @@ -2284,7 +2283,7 @@ lp->stats.tx_errors++; } -static void hp100_clear_stats( int ioaddr ) +static void hp100_clear_stats( struct hp100_private *lp, int ioaddr ) { unsigned long flags; @@ -2293,14 +2292,13 @@ printk("hp100: %s: clear_stats\n", dev->name); #endif - save_flags( flags ); - cli(); + spin_lock_irqsave (&lp->lock, flags); hp100_page( MAC_CTRL ); /* get all statistics bytes */ hp100_inw( DROPPED ); hp100_inb( CRC ); hp100_inb( ABORT ); hp100_page( PERFORMANCE ); - restore_flags( flags ); + spin_unlock_irqrestore (&lp->lock, flags); } @@ -2323,8 +2321,7 @@ printk("hp100: %s: set_mc_list\n", dev->name); #endif - save_flags( flags ); - cli(); + spin_lock_irqsave (&lp->lock, flags); hp100_ints_off(); hp100_page( MAC_CTRL ); hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ @@ -2457,7 +2454,7 @@ hp100_page( PERFORMANCE ); hp100_ints_on(); - restore_flags( flags ); + spin_unlock_irqrestore (&lp->lock, flags); } @@ -2475,11 +2472,10 @@ if ( dev == NULL ) return; ioaddr = dev->base_addr; + + spin_lock (&lp->lock); - if ( dev->interrupt ) - printk( "hp100: %s: re-entering the interrupt handler\n", dev->name ); hp100_ints_off(); - dev->interrupt = 1; /* mark that we are inside the handler */ #ifdef HP100_DEBUG_B hp100_outw( 0x4219, TRACE ); @@ -2501,7 +2497,7 @@ if(val==0) /* might be a shared interrupt */ { - dev->interrupt=0; + spin_unlock (&lp->lock); hp100_ints_on(); return; } @@ -2598,8 +2594,8 @@ } hp100_misc_interrupt( dev ); } - - dev->interrupt = 0; + + spin_unlock (&lp->lock); hp100_ints_on(); } @@ -2619,8 +2615,7 @@ printk("hp100: %s: hp100_start_interface\n",dev->name); #endif - save_flags( flags ); - cli(); + spin_lock_irqsave (&lp->lock, flags); /* Ensure the adapter does not want to request an interrupt when */ /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ @@ -2671,7 +2666,7 @@ /* Enable MAC Tx and RX, set MAC modes, ... */ hp100_set_multicast_list( dev ); - restore_flags( flags ); + spin_unlock_irqrestore (&lp->lock, flags); } diff -u --recursive --new-file v2.3.42/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c --- v2.3.42/linux/drivers/net/irda/nsc-ircc.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/irda/nsc-ircc.c Tue Feb 8 18:48:39 2000 @@ -41,9 +41,7 @@ * ********************************************************************/ -#include #include - #include #include #include @@ -58,9 +56,7 @@ #include #include -#ifdef CONFIG_APM -#include -#endif +#include #include #include @@ -144,9 +140,7 @@ static int nsc_ircc_net_close(struct net_device *dev); static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); -#ifdef CONFIG_APM -static int nsc_ircc_apmproc(apm_event_t event); -#endif /* CONFIG_APM */ +static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); /* * Function nsc_ircc_init () @@ -216,11 +210,6 @@ } } -#ifdef CONFIG_APM - /* Make sure at least one chip was found before enabling APM */ - if (ret == 0) - apm_register_callback(nsc_ircc_apmproc); -#endif /* CONFIG_APM */ return ret; } @@ -236,9 +225,7 @@ { int i; -#ifdef CONFIG_APM - apm_unregister_callback(nsc_ircc_apmproc); -#endif /* CONFIG_APM */ + pm_unregister_all(nsc_ircc_pmproc); for (i=0; i < 4; i++) { if (dev_self[i]) @@ -257,6 +244,7 @@ { struct net_device *dev; struct nsc_ircc_cb *self; + struct pm_dev *pmdev; int ret; int err; @@ -380,6 +368,10 @@ self->io.dongle_id = dongle_id; nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); + pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc); + if (pmdev) + pmdev->data = self; + return 0; } @@ -1984,7 +1976,6 @@ return &self->stats; } -#ifdef CONFIG_APM static void nsc_ircc_suspend(struct nsc_ircc_cb *self) { MESSAGE("%s, Suspending\n", driver_name); @@ -2019,36 +2010,21 @@ self->io.suspended = 0; } -static int nsc_ircc_apmproc(apm_event_t event) +static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) { - static int down = 0; /* Filter out double events */ - int i; - - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - if (!down) { - for (i=0; i<4; i++) { - if (dev_self[i]) - nsc_ircc_suspend(dev_self[i]); - } - } - down = 1; - break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - if (down) { - for (i=0; i<4; i++) { - if (dev_self[i]) - nsc_ircc_wakeup(dev_self[i]); - } - } - down = 0; - break; - } + struct nsc_ircc_cb *self = (struct nsc_ircc_cb*) dev->data; + if (self) { + switch (rqst) { + case PM_SUSPEND: + nsc_ircc_suspend(self); + break; + case PM_RESUME: + nsc_ircc_wakeup(self); + break; + } + } return 0; } -#endif /* CONFIG_APM */ #ifdef MODULE MODULE_AUTHOR("Dag Brattli "); diff -u --recursive --new-file v2.3.42/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c --- v2.3.42/linux/drivers/net/irda/smc-ircc.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/irda/smc-ircc.c Tue Feb 8 18:48:47 2000 @@ -33,9 +33,7 @@ * ********************************************************************/ -#include #include - #include #include #include @@ -51,9 +49,7 @@ #include #include -#ifdef CONFIG_APM -#include -#endif +#include #include #include @@ -91,9 +87,7 @@ static int ircc_net_open(struct net_device *dev); static int ircc_net_close(struct net_device *dev); -#ifdef CONFIG_APM -static int ircc_apmproc(apm_event_t event); -#endif /* CONFIG_APM */ +static int ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); /* These are the currently known SMC chipsets */ static smc_chip_t chips[] = @@ -291,6 +285,10 @@ irport_start(self->irport); + self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ircc_pmproc); + if (self->pmdev) + self->pmdev->data = self; + return 0; } @@ -999,7 +997,6 @@ return 0; } -#ifdef CONFIG_APM static void ircc_suspend(struct ircc_cb *self) { int i = 10; @@ -1031,36 +1028,21 @@ MESSAGE("%s, Waking up\n", driver_name); } -static int ircc_apmproc(apm_event_t event) +static int ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) { - static int down = 0; /* Filter out double events */ - int i; - - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - if (!down) { - for (i=0; i<4; i++) { - if (dev_self[i]) - ircc_suspend(dev_self[i]); - } - } - down = 1; - break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - if (down) { - for (i=0; i<4; i++) { - if (dev_self[i]) - ircc_wakeup(dev_self[i]); - } - } - down = 0; - break; - } + struct ircc_cb *self = (struct ircc_cb*) dev->data; + if (self) { + switch (rqst) { + case PM_SUSPEND: + ircc_suspend(self); + break; + case PM_RESUME: + ircc_wakeup(self); + break; + } + } return 0; } -#endif /* CONFIG_APM */ #ifdef MODULE MODULE_AUTHOR("Thomas Davis "); diff -u --recursive --new-file v2.3.42/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.3.42/linux/drivers/net/irda/toshoboe.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/irda/toshoboe.c Tue Feb 8 18:48:57 2000 @@ -56,7 +56,6 @@ /* No user servicable parts below here */ #include -#include #include #include #include @@ -77,9 +76,8 @@ #include #include -#ifdef CONFIG_APM -#include -#endif +#include +static int toshoboe_pmproc (struct pm_dev *dev, pm_request_t rqst, void *data); #include @@ -690,6 +688,7 @@ { struct toshoboe_cb *self; struct net_device *dev; + struct pm_dev *pmdev; int i = 0; int ok = 0; int err; @@ -858,6 +857,10 @@ return -1; } + 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 printk ("single"); @@ -869,7 +872,6 @@ return (0); } -#ifdef CONFIG_APM static void toshoboe_gotosleep (struct toshoboe_cb *self) { @@ -935,52 +937,23 @@ } static int -toshoboe_apmproc (apm_event_t event) +toshoboe_pmproc (struct pm_dev *dev, pm_request_t rqst, void *data) { - static int down = 0; /*Filter out double events */ - int i; - - switch (event) - { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - if (!down) - { - - for (i = 0; i < 4; i++) - { - if (dev_self[i]) - toshoboe_gotosleep (dev_self[i]); - } - - } - down = 1; - break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - if (down) - { - - - - for (i = 0; i < 4; i++) - { - if (dev_self[i]) - toshoboe_wakeup (dev_self[i]); - } - - - - } - down = 0; - break; - } + 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; } -#endif - int __init toshoboe_init (void) { struct pci_dev *pci_dev = NULL; @@ -997,7 +970,7 @@ pci_dev->irq); if (!toshoboe_open (pci_dev)) - found++; + found++; } } @@ -1006,9 +979,6 @@ if (found) { -#ifdef CONFIG_APM - apm_register_callback (toshoboe_apmproc); -#endif return 0; } @@ -1030,10 +1000,7 @@ toshoboe_close (dev_self[i]); } -#ifdef CONFIG_APM - apm_unregister_callback (toshoboe_apmproc); -#endif - + pm_unregister_all (toshoboe_pmproc); } diff -u --recursive --new-file v2.3.42/linux/drivers/net/loopback.c linux/drivers/net/loopback.c --- v2.3.42/linux/drivers/net/loopback.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/loopback.c Wed Feb 9 20:08:09 2000 @@ -107,17 +107,10 @@ return (struct net_device_stats *)dev->priv; } -static int loopback_open(struct net_device *dev) -{ - dev->flags|=IFF_LOOPBACK; - return 0; -} - /* Initialize the rest of the LOOPBACK device. */ int __init loopback_init(struct net_device *dev) { dev->mtu = LOOPBACK_MTU; - dev->tbusy = 0; dev->hard_start_xmit = loopback_xmit; dev->hard_header = eth_header; dev->hard_header_cache = eth_header_cache; @@ -127,7 +120,6 @@ dev->tx_queue_len = 0; dev->type = ARPHRD_LOOPBACK; /* 0x0001 */ dev->rebuild_header = eth_rebuild_header; - dev->open = loopback_open; dev->flags = IFF_LOOPBACK; dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) diff -u --recursive --new-file v2.3.42/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.3.42/linux/drivers/net/ltpc.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/ltpc.c Thu Feb 10 12:24:54 2000 @@ -1250,8 +1250,12 @@ } /* handles "ltpc=io,irq,dma" kernel command lines */ -void __init ltpc_setup(char *str, int *ints) +static int __init ltpc_setup(char *str) { + int ints[5]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] == 0) { if (str && !strncmp(str, "auto", 4)) { /* do nothing :-) */ @@ -1261,21 +1265,23 @@ printk (KERN_ERR "ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n"); } - return; + return 1; } else { io = ints[1]; if (ints[0] > 1) { irq = ints[2]; - return; + return 1; } if (ints[0] > 2) { dma = ints[3]; - return; + return 1; } /* ignore any other paramters */ } - return; + return 1; } + +__setup("ltpc=", ltpc_setup); #ifdef MODULE diff -u --recursive --new-file v2.3.42/linux/drivers/net/mace.c linux/drivers/net/mace.c --- v2.3.42/linux/drivers/net/mace.c Thu Nov 11 20:11:41 1999 +++ linux/drivers/net/mace.c Thu Feb 10 12:24:54 2000 @@ -5,17 +5,15 @@ * Copyright (C) 1996 Paul Mackerras. */ -#ifdef MODULE #include #include -#endif - #include #include #include #include #include #include +#include #include #include #include @@ -101,7 +99,7 @@ return d; } -int mace_probe(void) +static int __init mace_probe (void) { int j, rev; struct net_device *dev; @@ -111,6 +109,11 @@ static int maces_found = 0; static struct device_node *next_mace; +#ifdef MODULE + if(mace_devs != NULL) + return -EBUSY; +#endif + if (!maces_found) { next_mace = find_devices("mace"); maces_found = 1; @@ -894,25 +897,13 @@ } } -#ifdef MODULE -#if LINUX_VERSION_CODE > 0x20118 MODULE_AUTHOR("Paul Mackerras"); MODULE_DESCRIPTION("PowerMac MACE driver."); -#endif -int init_module(void) -{ - int res; - - if(mace_devs != NULL) - return -EBUSY; - res = mace_probe(); - return res; -} - -void cleanup_module(void) +static void __exit mace_cleanup (void) { +#ifdef MODULE struct mace_data *mp = (struct mace_data *) mace_devs->priv; unregister_netdev(mace_devs); @@ -922,6 +913,8 @@ kfree(mace_devs); mace_devs = NULL; +#endif } -#endif +module_init(mace_probe); +module_exit(mace_cleanup); diff -u --recursive --new-file v2.3.42/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.3.42/linux/drivers/net/myri_sbus.c Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/myri_sbus.c Thu Feb 10 12:24:54 2000 @@ -551,7 +551,6 @@ DIRQ(("IRQ_DISAB ")); myri_disable_irq(lregs, mp->cregs); - dev->interrupt = 1; softstate = sbus_readl(&chan->state); DIRQ(("state[%08x] ", softstate)); if (softstate != STATE_READY) { @@ -562,7 +561,6 @@ myri_rx(mp, dev); DIRQ(("\nistat=ISTAT_HOST ")); sbus_writel(ISTAT_HOST, lregs + LANAI_ISTAT); - dev->interrupt = 0; DIRQ(("IRQ_ENAB ")); myri_enable_irq(lregs, mp->cregs); } @@ -584,6 +582,17 @@ return 0; } +static void myri_tx_timeout(struct net_device *dev) +{ + struct myri_eth *mp = (struct myri_eth *) dev->priv; + + printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + + mp->enet_stats.tx_errors++; + myri_init(mp, 0); + netif_start_queue(dev); +} + static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct myri_eth *mp = (struct myri_eth *) dev->priv; @@ -598,29 +607,7 @@ myri_tx(mp, dev); - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - - DTX(("tbusy tickssofar[%d] ", tickssofar)); - if (tickssofar < 40) { - DTX(("returning 1\n")); - return 1; - } else { - DTX(("resetting, return 0\n")); - printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); - mp->enet_stats.tx_errors++; - myri_init(mp, in_interrupt()); - dev->tbusy = 0; - dev->trans_start = jiffies; - return 0; - } - } - - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { - DTX(("tbusy, maybe a race? returning 1\n")); - printk("%s: Transmitter access conflict.\n", dev->name); - return 1; - } + netif_stop_queue(dev); /* This is just to prevent multiple PIO reads for TX_BUFFS_AVAIL. */ head = sbus_readl(&sq->head); @@ -677,7 +664,7 @@ bang_the_chip(mp); DTX(("tbusy=0, returning 0\n")); - dev->tbusy = 0; + netif_start_queue(dev); restore_flags(flags); return 0; } @@ -1059,6 +1046,8 @@ dev->open = &myri_open; dev->stop = &myri_close; dev->hard_start_xmit = &myri_start_xmit; + dev->tx_timeout = &myri_tx_timeout; + dev->watchdog_timeo = 5*HZ; dev->get_stats = &myri_get_stats; dev->set_multicast_list = &myri_set_multicast; dev->irq = sdev->irqs[0]; @@ -1105,7 +1094,7 @@ return 0; } -int __init myri_sbus_probe(void) +static int __init myri_sbus_probe(void) { struct net_device *dev = NULL; struct sbus_bus *bus; @@ -1113,6 +1102,10 @@ static int called = 0; int cards = 0, v; +#ifdef MODULE + root_myri_dev = NULL; +#endif + if (called) return ENODEV; called++; @@ -1134,18 +1127,9 @@ return 0; } -#ifdef MODULE - -int -init_module(void) -{ - root_myri_dev = NULL; - return myri_sbus_probe(); -} - -void -cleanup_module(void) +static void __exit myri_sbus_cleanup(void) { +#ifdef MODULE /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_myri_dev) { struct myri_eth *next = root_myri_dev->next_module; @@ -1154,6 +1138,8 @@ kfree(root_myri_dev->dev); root_myri_dev = next; } +#endif /* MODULE */ } -#endif /* MODULE */ +module_init(myri_sbus_probe); +module_exit(myri_sbus_cleanup); diff -u --recursive --new-file v2.3.42/linux/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c --- v2.3.42/linux/drivers/net/ncr885e.c Thu Nov 11 20:11:41 1999 +++ linux/drivers/net/ncr885e.c Thu Feb 10 12:29:58 2000 @@ -14,18 +14,8 @@ "ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n"; #include - -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif #include #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include #include #include @@ -91,6 +81,8 @@ int ncr885e_debug = NCR885E_DEBUG; static int print_version = 0; +static int debug = NCR885E_DEBUG; /* module parm */ + struct ncr885e_private { @@ -124,10 +116,7 @@ spinlock_t lock; }; -#ifdef MODULE static struct net_device *root_dev = NULL; -#endif - static int ncr885e_open( struct net_device *dev ); static int ncr885e_close( struct net_device *dev ); @@ -1169,13 +1158,18 @@ unsigned char *p; int i; + if (!request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name)) + return -EBUSY; + dev = init_etherdev(NULL, 0 ); /* construct private data for the 885 ethernet */ dev->priv = kmalloc( sizeof( struct ncr885e_private ), GFP_KERNEL ); - if ( dev->priv == NULL ) + if ( dev->priv == NULL ) { + release_region( ioaddr, NCR885E_TOTAL_SIZE ); return -ENOMEM; + } sp = (struct ncr885e_private *) dev->priv; memset( sp, 0, sizeof( struct ncr885e_private )); @@ -1198,8 +1192,6 @@ printk(", IRQ %d.\n", irq ); - request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name ); - /* set up a timer */ init_timer( &sp->tx_timeout ); sp->timeout_active = 0; @@ -1216,6 +1208,8 @@ dev->hard_start_xmit = ncr885e_xmit_start; dev->set_multicast_list = ncr885e_set_multicast; dev->set_mac_address = ncr885e_set_address; + + root_dev = dev; return 0; } @@ -1226,13 +1220,16 @@ * worry about the rest. */ -int __init ncr885e_probe(void) +static int __init ncr885e_probe(void) { struct pci_dev *pdev = NULL; unsigned int ioaddr, chips = 0; unsigned short cmd; unsigned char irq, latency; + if ( debug >= 0) + ncr885e_debug = debug; + while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C885_ETHERNET, pdev )) != NULL ) { @@ -1416,26 +1413,12 @@ #endif /* NCR885E_DEBUG_MII */ -#ifdef MODULE -#if defined(LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20118 MODULE_AUTHOR("dan@synergymicro.com"); MODULE_DESCRIPTION("Symbios 53C885 Ethernet driver"); MODULE_PARM(debug, "i"); -#endif -static int debug = 1; -int -init_module(void) -{ - if ( debug >= 0) - ncr885e_debug = debug; - - return ncr885e_probe(); -} - -void -cleanup_module(void) +static void __exit ncr885e_cleanup (void) { struct ncr885e_private *np; @@ -1448,7 +1431,10 @@ root_dev = NULL; } } -#endif /* MODULE */ + +module_init(ncr885e_probe); +module_exit(ncr885e_cleanup); + /* * Local variables: diff -u --recursive --new-file v2.3.42/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.3.42/linux/drivers/net/ne.c Fri Oct 15 15:25:13 1999 +++ linux/drivers/net/ne.c Thu Feb 10 12:24:54 2000 @@ -606,9 +606,8 @@ if (ei_status.dmaing) { printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } @@ -646,9 +645,8 @@ if (ei_status.dmaing) { printk(KERN_EMERG "%s: DMAing conflict in ne_block_input " - "[DMAstat:%d][irqlock:%d][intr:%ld].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -721,9 +719,8 @@ if (ei_status.dmaing) { printk(KERN_EMERG "%s: DMAing conflict in ne_block_output." - "[DMAstat:%d][irqlock:%d][intr:%ld]\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); + "[DMAstat:%d][irqlock:%d]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; diff -u --recursive --new-file v2.3.42/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.3.42/linux/drivers/net/ne2k-pci.c Thu Nov 11 20:11:41 1999 +++ linux/drivers/net/ne2k-pci.c Thu Feb 10 12:24:54 2000 @@ -104,7 +104,7 @@ #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -int ne2k_pci_probe(void); +static int ne2k_pci_probe(void); static struct net_device *ne2k_pci_probe1(long ioaddr, int irq, int chip_idx); static int ne2k_pci_open(struct net_device *dev); @@ -129,10 +129,7 @@ /* A list of all installed devices, for removing the driver module. */ static struct ne2k_pci_card *ne2k_card_list = NULL; -#ifdef MODULE - -int -init_module(void) +static int __init ne2k_pci_init_module(void) { /* We must emit version information. */ if (debug) @@ -146,8 +143,7 @@ return 0; } -void -cleanup_module(void) +static void __exit ne2k_pci_cleanup_module(void) { struct net_device *dev; struct ne2k_pci_card *this_card; @@ -165,7 +161,8 @@ unlock_8390_module(); } -#endif /* MODULE */ +module_init(ne2k_pci_init_module); +module_exit(ne2k_pci_cleanup_module); /* NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet @@ -185,7 +182,7 @@ {"ne2k_pci", ne2k_pci_probe1, NE_IO_EXTENT, 0}; #endif -int __init ne2k_pci_probe(void) +static int __init ne2k_pci_probe(void) { struct pci_dev *pdev = NULL; int cards_found = 0; @@ -216,13 +213,11 @@ if (check_region(pci_ioaddr, NE_IO_EXTENT)) continue; -#ifndef MODULE { static unsigned version_printed = 0; if (version_printed++ == 0) printk(KERN_INFO "%s", version); } -#endif /* Activate the card: fix for brain-damaged Win98 BIOSes. */ new_command = pci_command | PCI_COMMAND_IO; @@ -451,9 +446,8 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr " - "[DMAstat:%d][irqlock:%d][intr:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - (int)dev->interrupt); + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } @@ -490,9 +484,8 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_block_input " - "[DMAstat:%d][irqlock:%d][intr:%d].\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - (int)dev->interrupt); + "[DMAstat:%d][irqlock:%d].\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -543,9 +536,8 @@ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) { printk("%s: DMAing conflict in ne2k_pci_block_output." - "[DMAstat:%d][irqlock:%d][intr:%d]\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - (int)dev->interrupt); + "[DMAstat:%d][irqlock:%d]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; diff -u --recursive --new-file v2.3.42/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.3.42/linux/drivers/net/net_init.c Thu Nov 11 20:11:41 1999 +++ linux/drivers/net/net_init.c Wed Feb 9 20:08:09 2000 @@ -153,7 +153,7 @@ static int eth_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr=p; - if(dev->start) + if(test_bit(LINK_STATE_START, &dev->state)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); return 0; @@ -200,7 +200,7 @@ static int hippi_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; - if(dev->start) + if(test_bit(LINK_STATE_START, &dev->state)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); return 0; diff -u --recursive --new-file v2.3.42/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c --- v2.3.42/linux/drivers/net/ni5010.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/ni5010.c Thu Feb 10 12:24:54 2000 @@ -186,7 +186,7 @@ { static unsigned version_printed = 0; int i; - unsigned int data; + unsigned int data = 0; int boguscount = 40; /* diff -u --recursive --new-file v2.3.42/linux/drivers/net/ni65.c linux/drivers/net/ni65.c --- v2.3.42/linux/drivers/net/ni65.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/ni65.c Thu Feb 10 12:24:54 2000 @@ -808,7 +808,7 @@ */ static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs) { - int csr0; + int csr0 = 0; struct net_device *dev = dev_id; struct priv *p; int bcnt = 32; diff -u --recursive --new-file v2.3.42/linux/drivers/net/oaknet.c linux/drivers/net/oaknet.c --- v2.3.42/linux/drivers/net/oaknet.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/oaknet.c Thu Feb 10 12:24:54 2000 @@ -1,6 +1,6 @@ /* * - * Copyright (c) 1999 Grant Erickson + * Copyright (c) 1999-2000 Grant Erickson * * Module name: oaknet.c * @@ -9,12 +9,17 @@ * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the * various other 8390 drivers written by Donald Becker and Paul Gortmaker. * + * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc. + * and "enetLib.c" from IBM. + * */ #include #include +#include #include #include +#include #include #include @@ -32,23 +37,23 @@ #define FALSE 0 #endif -#define OAKNET_CMD 0x00 -#define OAKNET_DATA 0x10 /* NS-defined port window offset. */ -#define OAKNET_RESET 0x1f /* A read resets, a write clears. */ - #define OAKNET_START_PG 0x20 /* First page of TX buffer */ #define OAKNET_STOP_PG 0x40 /* Last pagge +1 of RX ring */ -#define OAKNET_BASE (dev->base_addr) - #define OAKNET_WAIT (2 * HZ / 100) /* 20 ms */ +/* Experimenting with some fixes for a broken driver... */ + +#define OAKNET_DISINT +#define OAKNET_HEADCHECK +#define OAKNET_RWFIX + /* Global Variables */ -#if defined(MODULE) -static struct net_device *oaknet_devs; -#endif +static const char *name = "National DP83902AV"; + +static struct net_device *oaknet_devs = NULL; /* Function Prototypes */ @@ -85,20 +90,35 @@ * 0 if OK, otherwise system error number on error. * */ -int -oaknet_init(void) +static int __init oaknet_init(void) { register int i; int reg0, regd; - struct net_device *dev = NULL; - unsigned long ioaddr = OAKNET_IO_BASE; - const char *name = "National DP83902AV"; + struct net_device tmp, *dev = NULL; +#if 0 + unsigned long ioaddr = OAKNET_IO_BASE; +#else + unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE); +#endif bd_t *bip = (bd_t *)__res; + /* + * This MUST happen here because of the nic_* macros + * which have an implicit dependency on dev->base_addr. + */ + + tmp.base_addr = ioaddr; + dev = &tmp; + + if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) + return -EBUSY; + /* Quick register check to see if the device is really there. */ - if ((reg0 = inb_p(ioaddr)) == 0xFF) + if ((reg0 = ei_ibp(ioaddr)) == 0xFF) { + release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); return (ENODEV); + } /* * That worked. Now a more thorough check, using the multicast @@ -106,19 +126,20 @@ * and semi-functional. */ - outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD); - regd = inb_p(ioaddr + 0x0D); - outb_p(0xFF, ioaddr + 0x0D); - outb_p(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD); - inb_p(ioaddr + EN0_COUNTER0); + ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD); + regd = ei_ibp(ioaddr + 0x0D); + ei_obp(0xFF, ioaddr + 0x0D); + ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD); + ei_ibp(ioaddr + EN0_COUNTER0); /* It's no good. Fix things back up and leave. */ - if (inb_p(ioaddr + EN0_COUNTER0) != 0) { - outb_p(reg0, ioaddr); - outb_p(regd, ioaddr + 0x0D); + if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) { + ei_obp(reg0, ioaddr); + ei_obp(regd, ioaddr + 0x0D); dev->base_addr = 0; + release_region(dev->base_addr, OAKNET_IO_SIZE); return (ENODEV); } @@ -127,8 +148,10 @@ * sure its symbols are loaded. */ - if (load_8390_module("oaknet.c")) + if (load_8390_module("oaknet.c")) { + release_region(dev->base_addr, OAKNET_IO_SIZE); return (-ENOSYS); + } /* * We're not using the old-style probing API, so we have to allocate @@ -136,39 +159,31 @@ */ dev = init_etherdev(0, 0); -#if defined(MODULE) oaknet_devs = dev; -#endif /* * This controller is on an embedded board, so the base address * and interrupt assignments are pre-assigned and unchageable. */ - dev->base_addr = OAKNET_IO_BASE; + dev->base_addr = ioaddr; dev->irq = OAKNET_INT; /* Allocate 8390-specific device-private area and fields. */ if (ethdev_init(dev)) { printk(" unable to get memory for dev->priv.\n"); + release_region(dev->base_addr, OAKNET_IO_SIZE); return (-ENOMEM); } /* - * Just to be safe, reset the card as we cannot really* be sure - * what state it was last left in. - */ - - oaknet_reset_8390(dev); - - /* * Disable all chip interrupts for now and ACK all pending * interrupts. */ - outb_p(0x0, ioaddr + EN0_IMR); - outb_p(0xFF, ioaddr + EN0_ISR); + ei_obp(0x0, ioaddr + EN0_IMR); + ei_obp(0xFF, ioaddr + EN0_ISR); /* Attempt to get the interrupt line */ @@ -176,12 +191,10 @@ printk("%s: unable to request interrupt %d.\n", dev->name, dev->irq); kfree(dev->priv); - dev->priv = NULL; + release_region(dev->base_addr, OAKNET_IO_SIZE); return (EAGAIN); } - request_region(dev->base_addr, OAKNET_IO_SIZE, name); - /* Tell the world about what and where we've found. */ printk("%s: %s at", dev->name, name); @@ -273,7 +286,7 @@ * This routine resets the DP83902 chip. * * Input(s): - * *dev - + * *dev - Pointer to the device structure for this driver. * * Output(s): * N/A @@ -285,36 +298,48 @@ static void oaknet_reset_8390(struct net_device *dev) { - int base = OAKNET_BASE; - unsigned long start = jiffies; + int base = E8390_BASE; - outb(inb(base + OAKNET_RESET), base + OAKNET_RESET); + /* + * We have no provision of reseting the controller as is done + * in other drivers, such as "ne.c". However, the following + * seems to work well enough in the TiVo driver. + */ + printk("Resetting %s...\n", dev->name); + ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD); ei_status.txing = 0; ei_status.dmaing = 0; - /* This check shouldn't be necessary eventually */ - - while ((inb_p(base + EN0_ISR) & ENISR_RESET) == 0) { - if (jiffies - start > OAKNET_WAIT) { - printk("%s: reset didn't complete\n", dev->name); - break; - } - } - - outb_p(ENISR_RESET, base + EN0_ISR); /* ACK reset interrupt */ - return; } /* - * XXX - Document me. + * static void oaknet_get_8390_hdr() + * + * Description: + * This routine grabs the 8390-specific header. It's similar to the + * block input routine, but we don't need to be concerned with ring wrap + * as the header will be at the start of a page, so we optimize accordingly. + * + * Input(s): + * *dev - Pointer to the device structure for this driver. + * *hdr - Pointer to storage for the 8390-specific packet header. + * ring_page - ? + * + * Output(s): + * *hdr - Pointer to the 8390-specific packet header for the just- + * received frame. + * + * Returns: + * N/A + * */ static void oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { - int base = OAKNET_BASE; + int base = dev->base_addr; /* * This should NOT happen. If it does, it is the LAST thing you'll @@ -341,6 +366,10 @@ insb(base + OAKNET_DATA, hdr, sizeof(struct e8390_pkt_hdr)); + /* Byte-swap the packet byte count */ + + hdr->count = le16_to_cpu(hdr->count); + outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ ei_status.dmaing &= ~0x01; @@ -367,38 +396,99 @@ return; } +#ifdef OAKNET_DISINT + save_flags(flags); + cli(); +#endif + ei_status.dmaing |= 0x01; - outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD); - outb_p(count & 0xff, base + EN0_RCNTLO); - outb_p(count >> 8, base + EN0_RCNTHI); - outb_p(ring_offset & 0xff, base + EN0_RSARLO); - outb_p(ring_offset >> 8, base + EN0_RSARHI); - outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD); + ei_obp(E8390_NODMA + E8390_PAGE0 + E8390_START, base + E8390_CMD); + ei_obp(count & 0xff, base + EN0_RCNTLO); + ei_obp(count >> 8, base + EN0_RCNTHI); + ei_obp(ring_offset & 0xff, base + EN0_RSARLO); + ei_obp(ring_offset >> 8, base + EN0_RSARHI); + ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); if (ei_status.word16) { - insw(base + OAKNET_DATA, buf, count >> 1); + ei_isw(base + E8390_DATA, buf, count >> 1); if (count & 0x01) { - buf[count-1] = inb(base + OAKNET_DATA); + buf[count - 1] = ei_ib(base + E8390_DATA); +#ifdef OAKNET_HEADCHECK + bytes++; +#endif } } else { - insb(base + OAKNET_DATA, buf, count); + ei_isb(base + E8390_DATA, buf, count); } - outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ +#ifdef OAKNET_HEADCHECK + /* + * This was for the ALPHA version only, but enough people have + * been encountering problems so it is still here. If you see + * this message you either 1) have a slightly incompatible clone + * or 2) have noise/speed problems with your bus. + */ + + /* DMA termination address check... */ + { + int addr, tries = 20; + do { + /* DON'T check for 'ei_ibp(EN0_ISR) & ENISR_RDC' here + -- it's broken for Rx on some cards! */ + int high = ei_ibp(base + EN0_RSARHI); + int low = ei_ibp(base + EN0_RSARLO); + addr = (high << 8) + low; + if (((ring_offset + bytes) & 0xff) == low) + break; + } while (--tries > 0); + if (tries <= 0) + printk("%s: RX transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, ring_offset + bytes, addr); + } +#endif + ei_obp(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ ei_status.dmaing &= ~0x01; +#ifdef OAKNET_DISINT + restore_flags(flags); +#endif + return; } /* - * XXX - Document me. + * static void oaknet_block_output() + * + * Description: + * This routine... + * + * Input(s): + * *dev - Pointer to the device structure for this driver. + * count - Number of bytes to be transferred. + * *buf - + * start_page - + * + * Output(s): + * N/A + * + * Returns: + * N/A + * */ static void oaknet_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page) { - int base = OAKNET_BASE; + int base = E8390_BASE; +#if 0 int bug; +#endif unsigned long start; - unsigned char lobyte; +#ifdef OAKNET_DISINT + unsigned long flags; +#endif +#ifdef OAKNET_HEADCHECK + int retries = 0; +#endif /* Round the count up for word writes. */ @@ -415,12 +505,22 @@ return; } +#ifdef OAKNET_DISINT + save_flags(flags); + cli(); +#endif + ei_status.dmaing |= 0x01; /* Make sure we are in page 0. */ - outb_p(E8390_PAGE0 + E8390_START + E8390_NODMA, base + OAKNET_CMD); + ei_obp(E8390_PAGE0 + E8390_START + E8390_NODMA, base + E8390_CMD); +#ifdef OAKNET_HEADCHECK +retry: +#endif + +#if 0 /* * The 83902 documentation states that the processor needs to * do a "dummy read" before doing the remote write to work @@ -433,60 +533,131 @@ unsigned int rdlo; /* Now the normal output. */ - outb_p(ENISR_RDC, base + EN0_ISR); - outb_p(count & 0xff, base + EN0_RCNTLO); - outb_p(count >> 8, base + EN0_RCNTHI); - outb_p(0x00, base + EN0_RSARLO); - outb_p(start_page, base + EN0_RSARHI); + ei_obp(ENISR_RDC, base + EN0_ISR); + ei_obp(count & 0xff, base + EN0_RCNTLO); + ei_obp(count >> 8, base + EN0_RCNTHI); + ei_obp(0x00, base + EN0_RSARLO); + ei_obp(start_page, base + EN0_RSARHI); if (bug++) break; /* Perform the dummy read */ - rdhi = inb_p(base + EN0_CRDAHI); - rdlo = inb_p(base + EN0_CRDALO); - outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD); + rdhi = ei_ibp(base + EN0_CRDAHI); + rdlo = ei_ibp(base + EN0_CRDALO); + ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); while (1) { unsigned int nrdhi; unsigned int nrdlo; - nrdhi = inb_p(base + EN0_CRDAHI); - nrdlo = inb_p(base + EN0_CRDALO); + nrdhi = ei_ibp(base + EN0_CRDAHI); + nrdlo = ei_ibp(base + EN0_CRDALO); if ((rdhi != nrdhi) || (rdlo != nrdlo)) break; } } +#else +#ifdef OAKNET_RWFIX + /* + * Handle the read-before-write bug the same way as the + * Crynwr packet driver -- the Nat'l Semi. method doesn't work. + * Actually this doesn't always work either, but if you have + * problems with your 83902 this is better than nothing! + */ + + ei_obp(0x42, base + EN0_RCNTLO); + ei_obp(0x00, base + EN0_RCNTHI); + ei_obp(0x42, base + EN0_RSARLO); + ei_obp(0x00, base + EN0_RSARHI); + ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); + /* Make certain that the dummy read has occurred. */ + udelay(6); +#endif + + ei_obp(ENISR_RDC, base + EN0_ISR); - outb_p(E8390_RWRITE+E8390_START, base + OAKNET_CMD); + /* Now the normal output. */ + ei_obp(count & 0xff, base + EN0_RCNTLO); + ei_obp(count >> 8, base + EN0_RCNTHI); + ei_obp(0x00, base + EN0_RSARLO); + ei_obp(start_page, base + EN0_RSARHI); +#endif /* 0/1 */ + + ei_obp(E8390_RWRITE + E8390_START, base + E8390_CMD); if (ei_status.word16) { - outsw(OAKNET_BASE + OAKNET_DATA, buf, count >> 1); + ei_osw(E8390_BASE + E8390_DATA, buf, count >> 1); } else { - outsb(OAKNET_BASE + OAKNET_DATA, buf, count); + ei_osb(E8390_BASE + E8390_DATA, buf, count); } +#ifdef OAKNET_DISINT + restore_flags(flags); +#endif + start = jiffies; - while (((lobyte = inb_p(base + EN0_ISR)) & ENISR_RDC) == 0) { +#ifdef OAKNET_HEADCHECK + /* + * This was for the ALPHA version only, but enough people have + * been encountering problems so it is still here. + */ + + { + /* DMA termination address check... */ + int addr, tries = 20; + do { + int high = ei_ibp(base + EN0_RSARHI); + int low = ei_ibp(base + EN0_RSARLO); + addr = (high << 8) + low; + if ((start_page << 8) + count == addr) + break; + } while (--tries > 0); + + if (tries <= 0) { + printk("%s: Tx packet transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, (start_page << 8) + count, addr); + if (retries++ == 0) + goto retry; + } + } +#endif + + while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) { if (jiffies - start > OAKNET_WAIT) { - unsigned char hicnt, locnt; - hicnt = inb_p(base + EN0_CRDAHI); - locnt = inb_p(base + EN0_CRDALO); - printk("%s: timeout waiting for Tx RDC, stat = 0x%x\n", - dev->name, lobyte); - printk("\tstart address 0x%x, current address 0x%x, count %d\n", - (start_page << 8), (hicnt << 8) | locnt, count); + printk("%s: timeout waiting for Tx RDC.\n", dev->name); oaknet_reset_8390(dev); NS8390_init(dev, TRUE); break; } } - outb_p(ENISR_RDC, base + EN0_ISR); /* Ack intr. */ + ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; return; } +/* + * static void oaknet_dma_error() + * + * Description: + * This routine prints out a last-ditch informative message to the console + * indicating that a DMA error occured. If you see this, it's the last + * thing you'll see. + * + * Input(s): + * *dev - Pointer to the device structure for this driver. + * *name - Informative text (e.g. function name) indicating where the + * DMA error occurred. + * + * Output(s): + * N/A + * + * Returns: + * N/A + * + */ static void oaknet_dma_error(struct net_device *dev, const char *name) { @@ -498,12 +669,10 @@ return; } -#if defined(MODULE) /* * Oak Ethernet module load interface. */ -int -init_module(void) +static int __init oaknet_init_module (void) { int status; @@ -512,7 +681,8 @@ status = oaknet_init() - lock_8390_module(); + if (status == 0) + lock_8390_module(); return (status); } @@ -520,8 +690,7 @@ /* * Oak Ethernet module unload interface. */ -void -cleanup_module(void) +static void __exit oaknet_cleanup_module (void) { if (oaknet_devs == NULL) return; @@ -538,7 +707,7 @@ oaknet_devs = NULL; unlock_8390_module(); - - return; } -#endif /* MODULE */ + +module_init(oaknet_init_module); +module_exit(oaknet_cleanup_module); diff -u --recursive --new-file v2.3.42/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c --- v2.3.42/linux/drivers/net/pcmcia/pcnet_cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/pcmcia/pcnet_cs.c Wed Feb 9 21:15:22 2000 @@ -315,7 +315,8 @@ dev->open = &pcnet_open; dev->stop = &pcnet_close; dev->set_config = &set_config; - dev->tbusy = 1; + + netif_stop_queue(dev); /* Register with Card Services */ link->next = dev_list; @@ -681,7 +682,7 @@ } else { dev->if_port = 0; } - dev->tbusy = 0; + netif_start_queue(dev); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n"); goto failed; @@ -806,7 +807,8 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - info->dev.tbusy = 1; info->dev.start = 0; + netif_stop_queue(&info->dev); + clear_bit(LINK_STATE_START, &info->dev.state); link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; add_timer(&link->release); @@ -822,7 +824,8 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - info->dev.tbusy = 1; info->dev.start = 0; + netif_stop_queue(&info->dev); + clear_bit(LINK_STATE_START, &info->dev.state); } CardServices(ReleaseConfiguration, link->handle); } @@ -836,7 +839,8 @@ if (link->open) { pcnet_reset_8390(&info->dev); NS8390_init(&info->dev, 1); - info->dev.tbusy = 0; info->dev.start = 1; + netif_start_queue(&info->dev); + set_bit(LINK_STATE_START, &info->dev.state); } } break; @@ -903,7 +907,8 @@ free_irq(dev->irq, dev); - link->open--; dev->start = 0; + link->open--; + clear_bit(LINK_STATE_START, &dev->state); del_timer(&info->watchdog); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; @@ -979,7 +984,8 @@ struct net_device *dev = &info->dev; ioaddr_t nic_base = dev->base_addr; - if (dev->start == 0) goto reschedule; + if (!test_bit(LINK_STATE_START, &dev->state)) + goto reschedule; /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ @@ -1023,9 +1029,8 @@ if (ei_status.dmaing) { printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input." - "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - (long)dev->interrupt); + "[DMAstat:%1x][irqlock:%1x]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } @@ -1061,9 +1066,8 @@ #endif if (ei_status.dmaing) { printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input." - "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - (long)dev->interrupt); + "[DMAstat:%1x][irqlock:%1x]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; @@ -1127,9 +1131,8 @@ count++; if (ei_status.dmaing) { printk(KERN_NOTICE "%s: DMAing conflict in dma_block_output." - "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n", - dev->name, ei_status.dmaing, ei_status.irqlock, - (long)dev->interrupt); + "[DMAstat:%1x][irqlock:%1x]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); return; } ei_status.dmaing |= 0x01; diff -u --recursive --new-file v2.3.42/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c --- v2.3.42/linux/drivers/net/pcmcia/ray_cs.c Thu Jan 6 12:57:47 2000 +++ linux/drivers/net/pcmcia/ray_cs.c Wed Feb 9 21:22:02 2000 @@ -389,7 +389,7 @@ dev->init = &ray_dev_init; dev->open = &ray_open; dev->stop = &ray_dev_close; - dev->tbusy = 1; + netif_stop_queue(dev); /* Register with Card Services */ link->next = dev_list; @@ -926,7 +926,8 @@ switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; - dev->tbusy = 1; dev->start = 0; + netif_stop_queue(dev); + clear_bit(LINK_STATE_START, &dev->state); if (link->state & DEV_CONFIG) { link->release.expires = jiffies + HZ/20; add_timer(&link->release); @@ -943,8 +944,8 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); + clear_bit(LINK_STATE_START, &dev->state); } pcmcia_release_configuration(link->handle); } @@ -957,8 +958,8 @@ pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { ray_reset(dev); - dev->tbusy = 0; - dev->start = 1; + netif_start_queue(dev); + set_bit(LINK_STATE_START, &dev->state); } } break; @@ -1019,16 +1020,11 @@ return -1; } DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev); - if (dev->tbusy) - { - printk(KERN_NOTICE "ray_dev_start_xmit busy\n"); - return 1; - } if (local->authentication_state == NEED_TO_AUTH) { DEBUG(0,"ray_cs Sending authentication request.\n"); if (!build_auth_frame (local, local->auth_id, OPEN_AUTH_REQUEST)) { local->authentication_state = AUTHENTICATED; - dev->tbusy = 1; + netif_stop_queue(dev); return 1; } } @@ -1037,7 +1033,7 @@ switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) { case XMIT_NO_CCS: case XMIT_NEED_AUTH: - dev->tbusy = 1; + netif_stop_queue(dev); return 1; case XMIT_NO_INTR: case XMIT_MSG_BAD: @@ -1072,7 +1068,7 @@ case ECCSFULL: DEBUG(2,"ray_hw_xmit No free tx ccs\n"); case ECARDGONE: - dev->tbusy = 1; + netif_stop_queue(dev); return XMIT_NO_CCS; default: break; @@ -1175,7 +1171,7 @@ { if (local->sparm.b4.a_acting_as_ap_status) { - writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);; + writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2); memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, ADDRLEN); memcpy_toio(ptx->mac.addr_2, local->bss_id, 6); memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_source, ADDRLEN); @@ -1512,10 +1508,8 @@ link->open++; MOD_INC_USE_COUNT; - dev->interrupt = 0; - if (sniffer) dev->tbusy = 1; - else dev->tbusy = 0; - dev->start = 1; + if (sniffer) netif_stop_queue(dev); + else netif_start_queue(dev); DEBUG(2,"ray_open ending\n"); return 0; @@ -1532,7 +1526,8 @@ if (link == NULL) return -ENODEV; - link->open--; dev->start = 0; + link->open--; + netif_stop_queue(dev); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; @@ -1848,11 +1843,6 @@ DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); - if (test_and_set_bit(0,&dev->interrupt)) { - printk("ray_cs Reentering interrupt handler not allowed\n"); - return; - } - local = (ray_dev_t *)dev->priv; link = (dev_link_t *)local->finder; if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) { @@ -1865,7 +1855,6 @@ { DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex); clear_interrupt(local); - dev->interrupt = 0; return; } if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */ @@ -1961,8 +1950,8 @@ else { DEBUG(1,"ray_cs interrupt tx request failed\n"); } - if (!sniffer) dev->tbusy = 0; - mark_bh(NET_BH); + if (!sniffer) netif_start_queue(dev); + netif_wake_queue(dev); break; case CCS_TEST_MEMORY: DEBUG(1,"ray_cs interrupt mem test done\n"); @@ -1996,7 +1985,7 @@ local->card_status = CARD_ACQ_COMPLETE; /* do we need to clear tx buffers CCS's? */ if (local->sparm.b4.a_network_type == ADHOC) { - if (!sniffer) dev->tbusy = 0; + if (!sniffer) netif_start_queue(dev); } else { memcpy_fromio(&local->bss_id, prcs->var.rejoin_net_complete.bssid, ADDRLEN); @@ -2008,7 +1997,7 @@ break; case ROAMING_INITIATED: DEBUG(1,"ray_cs interrupt roaming initiated\n"); - dev->tbusy = 1; + netif_stop_queue(dev); local->card_status = CARD_DOING_ACQ; break; case JAPAN_CALL_SIGN_RXD: @@ -2022,7 +2011,6 @@ writeb(CCS_BUFFER_FREE, &prcs->buffer_status); } clear_interrupt(local); - dev->interrupt = 0; } /* ray_interrupt */ /*===========================================================================*/ static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs) @@ -2477,7 +2465,7 @@ local->card_status = CARD_ASSOC_FAILED; return; } - if (!sniffer) dev->tbusy = 0; + if (!sniffer) netif_start_queue(dev); } /* end associate */ /*===========================================================================*/ diff -u --recursive --new-file v2.3.42/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c --- v2.3.42/linux/drivers/net/pcnet32.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/pcnet32.c Thu Feb 10 12:26:47 2000 @@ -43,9 +43,7 @@ static int pcnet32_debug = 1; static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ -#ifdef MODULE static struct net_device *pcnet32_dev = NULL; -#endif static const int max_interrupt_work = 80; static const int rx_copybreak = 200; @@ -273,17 +271,16 @@ #endif full_duplex:1, /* full duplex possible */ mii:1; /* mii port available */ -#ifdef MODULE struct net_device *next; -#endif }; -int pcnet32_probe(void); +static int pcnet32_probe(void); static int pcnet32_probe1(unsigned long, unsigned char, int, int); static int pcnet32_open(struct net_device *); static int pcnet32_init_ring(struct net_device *); static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); static int pcnet32_rx(struct net_device *); +static void pcnet32_tx_timeout (struct net_device *dev); static void pcnet32_interrupt(int, void *, struct pt_regs *); static int pcnet32_close(struct net_device *); static struct net_device_stats *pcnet32_get_stats(struct net_device *); @@ -433,7 +430,7 @@ -int __init pcnet32_probe(void) +static int __init pcnet32_probe(void) { unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0; unsigned int irq_line = 0; // FIXME dev ? dev->irq : 0; @@ -754,12 +751,11 @@ #ifdef HAVE_PRIVATE_IOCTL dev->do_ioctl = &pcnet32_mii_ioctl; #endif + dev->tx_timeout = pcnet32_tx_timeout; + dev->watchdog_timeo = (HZ >> 1); - -#ifdef MODULE lp->next = pcnet32_dev; pcnet32_dev = dev; -#endif /* Fill in the generic fields of the device structure. */ ether_setup(dev); @@ -852,9 +848,8 @@ lp->a.write_csr (ioaddr, 4, 0x0915); lp->a.write_csr (ioaddr, 0, 0x0001); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); + i = 0; while (i++ < 100) if (lp->a.read_csr (ioaddr, 0) & 0x0100) @@ -963,20 +958,14 @@ lp->a.write_csr (ioaddr, 0, csr0_bits); } -static int -pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) + +static void +pcnet32_tx_timeout (struct net_device *dev) { struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; unsigned int ioaddr = dev->base_addr; - u16 status; - int entry; - unsigned long flags; /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < HZ/2) - return 1; printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, lp->a.read_csr (ioaddr, 0)); lp->a.write_csr (ioaddr, 0, 0x0004); @@ -998,24 +987,25 @@ } pcnet32_restart(dev, 0x0042); - dev->tbusy = 0; dev->trans_start = jiffies; - dev_kfree_skb(skb); - return 0; - } + netif_start_queue(dev); +} + + +static int +pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned int ioaddr = dev->base_addr; + u16 status; + int entry; + unsigned long flags; if (pcnet32_debug > 3) { printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name, lp->a.read_csr (ioaddr, 0)); } - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - return 1; - } - spin_lock_irqsave(&lp->lock, flags); /* Default status -- will not enable Successful-TxDone @@ -1059,7 +1049,7 @@ dev->trans_start = jiffies; if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) - clear_bit (0, (void *)&dev->tbusy); + netif_start_queue(dev); else lp->tx_full = 1; spin_unlock_irqrestore(&lp->lock, flags); @@ -1087,11 +1077,6 @@ spin_lock(&lp->lock); - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - - dev->interrupt = 1; - rap = lp->a.read_rap(ioaddr); while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) { /* Acknowledge all of the current interrupt sources ASAP. */ @@ -1167,12 +1152,12 @@ dirty_tx += TX_RING_SIZE; } #endif - if (lp->tx_full && dev->tbusy - && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + if (lp->tx_full && + test_bit(LINK_STATE_XOFF, &dev->flags) && + dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; - clear_bit(0, (void *)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (dev); } lp->dirty_tx = dirty_tx; } @@ -1213,10 +1198,7 @@ printk("%s: exiting interrupt, csr0=%#4.4x.\n", dev->name, lp->a.read_csr (ioaddr, 0)); - dev->interrupt = 0; - spin_unlock(&lp->lock); - return; } static int @@ -1317,8 +1299,7 @@ struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; int i; - dev->start = 0; - set_bit (0, (void *)&dev->tbusy); + netif_stop_queue(dev); lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112); @@ -1478,21 +1459,20 @@ } #endif /* HAVE_PRIVATE_IOCTL */ -#ifdef MODULE MODULE_PARM(debug, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(tx_start_pt, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); - +MODULE_AUTHOR("Thomas Bogendoerfer"); +MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards"); /* An additional parameter that may be passed in... */ static int debug = -1; static int tx_start_pt = -1; -int -init_module(void) +static int __init pcnet32_init_module(void) { if (debug > 0) pcnet32_debug = debug; @@ -1503,8 +1483,7 @@ return pcnet32_probe(); } -void -cleanup_module(void) +static void __exit pcnet32_cleanup_module(void) { struct net_device *next_dev; @@ -1518,10 +1497,10 @@ pcnet32_dev = next_dev; } } -#endif /* MODULE */ +module_init(pcnet32_init_module); +module_exit(pcnet32_cleanup_module); - /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c" diff -u --recursive --new-file v2.3.42/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.3.42/linux/drivers/net/plip.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/plip.c Thu Feb 10 12:26:47 2000 @@ -160,7 +160,6 @@ static int plip_open(struct net_device *dev); static int plip_close(struct net_device *dev); static struct net_device_stats *plip_get_stats(struct net_device *dev); -static int plip_config(struct net_device *dev, struct ifmap *map); static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static int plip_preempt(void *handle); static void plip_wakeup(void *handle); @@ -1256,9 +1255,7 @@ static struct net_device *dev_plip[PLIP_MAX] = { NULL, }; -#ifdef MODULE -void -cleanup_module(void) +static void __exit plip_cleanup_module (void) { int i; @@ -1278,14 +1275,16 @@ } } -#define plip_init init_module - -#else /* !MODULE */ +#ifndef MODULE static int parport_ptr = 0; -void plip_setup(char *str, int *ints) +static void __init plip_setup(char *str) { + int ints[4]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + /* Ugh. */ if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str+7, NULL, 10); @@ -1307,7 +1306,9 @@ } } -#endif /* MODULE */ +__setup("plip=", plip_setup); + +#endif /* !MODULE */ static int inline plip_searchfor(int list[], int a) @@ -1319,8 +1320,7 @@ return 0; } -int __init -plip_init(void) +static int __init plip_init (void) { struct parport *pb = parport_enumerate(); int i=0; @@ -1375,7 +1375,10 @@ } return 0; } - + +module_init(plip_init); +module_exit(plip_cleanup_module); + /* * Local variables: * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -c plip.c" diff -u --recursive --new-file v2.3.42/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c --- v2.3.42/linux/drivers/net/ppp_generic.c Thu Nov 11 20:11:41 1999 +++ linux/drivers/net/ppp_generic.c Wed Feb 9 20:08:09 2000 @@ -527,7 +527,7 @@ } else { ppp->npmode[i] = npi.mode; /* we may be able to transmit more packets now (??) */ - mark_bh(NET_BH); + netif_wake_queue(ppp->dev); } err = 0; break; @@ -539,16 +539,12 @@ } static struct file_operations ppp_device_fops = { - NULL, /* seek */ - ppp_read, - ppp_write, - NULL, /* readdir */ - ppp_poll, - ppp_ioctl, - NULL, /* mmap */ - ppp_open, - NULL, /* flush */ - ppp_release + read: ppp_read, + write: ppp_write, + poll: ppp_poll, + ioctl: ppp_ioctl, + open: ppp_open, + release: ppp_release }; #define PPP_MAJOR 108 @@ -630,11 +626,7 @@ pp[0] = proto >> 8; pp[1] = proto; - /* - * ppp->xq should only ever have more than 1 data packet on it - * if the core net code calls us when dev->tbusy == 1. - */ - dev->tbusy = 1; + netif_stop_queue(dev); skb_queue_tail(&ppp->xq, skb); if (trylock_xmit_path(ppp)) ppp_xmit_unlock(ppp, 0); @@ -735,12 +727,9 @@ while (ppp->xmit_pending == 0 && (skb = skb_dequeue(&ppp->xq)) != 0) ppp_send_frame(ppp, skb); - if (ppp->xmit_pending == 0 && skb_peek(&ppp->xq) == 0 - && ppp->dev->tbusy) { - ppp->dev->tbusy = 0; - if (do_mark_bh) - mark_bh(NET_BH); - } + if (ppp->xmit_pending == 0 && skb_peek(&ppp->xq) == 0) + netif_wake_queue(ppp->dev); + /* Now unlock the transmit path, let others in. */ unlock_xmit_path(ppp); /* Check whether any work was queued up diff -u --recursive --new-file v2.3.42/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c --- v2.3.42/linux/drivers/net/rcpci45.c Thu Nov 11 20:11:41 1999 +++ linux/drivers/net/rcpci45.c Thu Feb 10 12:26:47 2000 @@ -52,13 +52,13 @@ #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -67,14 +67,7 @@ #include /* For NR_IRQS only. */ #include #include - -#if LINUX_VERSION_CODE >= 0x020100 -#define LINUX_2_1 -#endif - -#ifdef LINUX_2_1 #include -#endif #include #include @@ -91,11 +84,6 @@ #define NEW_MULTICAST #include -#ifndef LINUX_2_1 -#define ioremap vremap -#define iounmap vfree -#endif - /* PCI/45 Configuration space values */ #define RC_PCI45_VENDOR_ID 0x4916 #define RC_PCI45_DEVICE_ID 0x1960 @@ -178,11 +166,7 @@ /* A list of all installed RC devices, for removing the driver module. */ static struct net_device *root_RCdev = NULL; -#ifdef MODULE -int init_module(void) -#else -int rcpci_probe(void) -#endif +static int __init rcpci_init_module (void) { int cards_found; @@ -562,11 +546,7 @@ printk("rc: skb = 0x%x\n", (uint)skb); #endif BufferContext++; -#ifdef LINUX_2_1 dev_kfree_skb (skb); -#else - dev_kfree_skb (skb, FREE_WRITE); -#endif } dev->tbusy = 0; @@ -727,18 +707,10 @@ while(PktCount--) { skb = (struct sk_buff *)PacketDescBlock[0]; -#ifndef LINUX_2_1 - skb->free = 1; - skb->lock = 0; -#endif #ifdef RCDEBUG printk("free skb 0x%p\n", skb); #endif -#ifdef LINUX_2_1 dev_kfree_skb (skb); -#else - dev_kfree_skb(skb, FREE_READ); -#endif pDpa->numOutRcvBuffers--; PacketDescBlock += BD_SIZE; /* point to next context field */ } @@ -777,12 +749,7 @@ if ( RCPostRecvBuffers(pDpa->id, (PRCTCB)ptcb ) != RC_RTN_NO_ERROR) { printk("rc: RCrecv_callback: post buffer failed!\n"); -#ifdef LINUX_2_1 dev_kfree_skb (skb); -#else - skb->free = 1; - dev_kfree_skb(skb, FREE_READ); -#endif } else { @@ -1089,17 +1056,8 @@ case RCU_COMMAND: { -#ifdef LINUX_2_1 if(copy_from_user(&RCuser, rq->ifr_data, sizeof(RCuser))) return -EFAULT; -#else - int error; - error=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(RCuser)); - if (error) { - return error; - } - memcpy_fromfs(&RCuser, rq->ifr_data, sizeof(RCuser)); -#endif #ifdef RCDEBUG printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd); @@ -1208,11 +1166,7 @@ RCUD_DEFAULT -> rc = 0x11223344; break; } -#ifdef LINUX_2_1 copy_to_user(rq->ifr_data, &RCuser, sizeof(RCuser)); -#else - memcpy_tofs(rq->ifr_data, &RCuser, sizeof(RCuser)); -#endif break; } /* RCU_COMMAND */ @@ -1243,9 +1197,7 @@ } -#ifdef MODULE -void -cleanup_module(void) +static void __exit rcpci_cleanup_module (void) { PDPA pDpa; struct net_device *next; @@ -1273,7 +1225,9 @@ root_RCdev = next; } } -#endif + +module_init(rcpci_init_module); +module_exit(rcpci_clenaup_module); static int @@ -1356,17 +1310,10 @@ while(p[0]) { skb = (struct sk_buff *)pB->context; -#ifndef LINUX_2_1 - skb->free = 1; -#endif #ifdef RCDEBUG printk("rc: freeing 0x%x\n", (uint)skb); #endif -#ifdef LINUX_2_1 dev_kfree_skb (skb); -#else - dev_kfree_skb(skb, FREE_READ); -#endif p[0]--; pB++; } diff -u --recursive --new-file v2.3.42/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c --- v2.3.42/linux/drivers/net/rtl8139.c Thu Nov 11 20:11:41 1999 +++ linux/drivers/net/rtl8139.c Wed Feb 9 20:08:09 2000 @@ -165,11 +165,12 @@ const char *name; u16 vendor_id, device_id, device_id_mask, flags; int io_size; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); + struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); }; -static struct net_device * rtl8129_probe1(int pci_bus, int pci_devfn, long ioaddr, - int irq, int chp_idx, int fnd_cnt); +static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus, + int pci_devfn, long ioaddr, + int irq, int chp_idx, int fnd_cnt); static struct pci_id_info pci_tbl[] = {{ "RealTek RTL8129 Fast Ethernet", @@ -249,10 +250,16 @@ {0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83} }; +struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + struct rtl8129_private { char devname[8]; /* Used only for kernel debugging. */ const char *product_name; struct net_device *next_module; + struct pci_dev *pdev; int chip_id; int chip_revision; unsigned char pci_bus, pci_devfn; @@ -265,10 +272,12 @@ unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ unsigned int cur_tx, dirty_tx, tx_flag; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[NUM_TX_DESC]; + struct ring_info tx_info[NUM_TX_DESC]; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ unsigned char *rx_ring; unsigned char *tx_bufs; /* Tx bounce buffer region. */ + dma_addr_t rx_ring_dma; + dma_addr_t tx_bufs_dma; char phys[4]; /* MII device addresses. */ char twistie, twist_cnt; /* Twister tune state. */ unsigned int tx_full:1; /* The Tx queue is full. */ @@ -328,6 +337,7 @@ return -ENODEV; for (; pci_index < 0xff; pci_index++) { + struct pci_dev *pdev; u16 vendor, device, pci_command, new_command; int chip_idx, irq; long ioaddr; @@ -349,22 +359,9 @@ if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ continue; - { -#if defined(PCI_SUPPORT_VER2) - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - ioaddr = pdev->resource[0].start; - irq = pdev->irq; -#else - u32 pci_ioaddr; - u8 pci_irq_line; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - ioaddr = pci_ioaddr & ~3; - irq = pci_irq_line; -#endif - } + pdev = pci_find_slot(pci_bus, pci_device_fn); + ioaddr = pdev->resource[0].start; + irq = pdev->irq; if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && check_region(ioaddr, pci_tbl[chip_idx].io_size)) @@ -382,7 +379,7 @@ PCI_COMMAND, new_command); } - dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found); + dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found); if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { u8 pci_latency; @@ -403,8 +400,9 @@ return cards_found ? 0 : -ENODEV; } -static struct net_device *rtl8129_probe1(int pci_bus, int pci_devfn, long ioaddr, - int irq, int chip_idx, int found_cnt) +static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus, + int pci_devfn, long ioaddr, + int irq, int chip_idx, int found_cnt) { static int did_version = 0; /* Already printed version info. */ struct rtl8129_private *tp; @@ -449,6 +447,7 @@ tp->next_module = root_rtl8129_dev; root_rtl8129_dev = dev; + tp->pdev = pdev; tp->chip_id = chip_idx; tp->pci_bus = pci_bus; tp->pci_devfn = pci_devfn; @@ -501,6 +500,8 @@ /* The Rtl8129-specific entries in the device structure. */ dev->open = &rtl8129_open; dev->hard_start_xmit = &rtl8129_start_xmit; + dev->tx_timeout = &rtl8129_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; dev->stop = &rtl8129_close; dev->get_stats = &rtl8129_get_stats; dev->set_multicast_list = &set_rx_mode; @@ -677,12 +678,22 @@ MOD_INC_USE_COUNT; - tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL); - tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL); + tp->tx_bufs = pci_alloc_consistent(tp->pdev, + TX_BUF_SIZE * NUM_TX_DESC, + &tp->tx_bufs_dma); + tp->rx_ring = pci_alloc_consistent(tp->pdev, + RX_BUF_LEN + 16, + &tp->rx_ring_dma); if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { free_irq(dev->irq, dev); if (tp->tx_bufs) - kfree(tp->tx_bufs); + pci_free_consistent(tp->pdev, + TX_BUF_SIZE * NUM_TX_DESC, + tp->tx_bufs, tp->tx_bufs_dma); + if (tp->rx_ring) + pci_free_consistent(tp->pdev, + RX_BUF_LEN + 16, + tp->rx_ring, tp->rx_ring_dma); if (rtl8129_debug > 0) printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", dev->name, RX_BUF_LEN); @@ -725,7 +736,7 @@ outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); outb(0x00, ioaddr + Cfg9346); - outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf); + outl(tp->rx_ring_dma, ioaddr + RxBuf); /* Start the chip's Tx and Rx process. */ outl(0, ioaddr + RxMissed); @@ -733,10 +744,6 @@ outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - /* Enable all known interrupts by setting the interrupt mask. */ outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); @@ -787,7 +794,8 @@ rtl8129_interrupt(dev->irq, dev, 0); } } - if (dev->tbusy && jiffies - dev->trans_start >= 2*TX_TIMEOUT) + if (test_bit(LINK_STATE_XOFF, &dev->state) && + (jiffies - dev->trans_start) >= 2*TX_TIMEOUT) rtl8129_tx_timeout(dev); #if 0 @@ -902,26 +910,40 @@ { /* Save the unsent Tx packets. */ struct sk_buff *saved_skb[NUM_TX_DESC], *skb; int j; - for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) - saved_skb[j] = tp->tx_skbuff[tp->dirty_tx % NUM_TX_DESC]; + for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) { + struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC]; + + saved_skb[j] = rp->skb; + if (rp->mapping != 0) { + pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len); + rp->mapping = 0; + } + } tp->dirty_tx = tp->cur_tx = 0; for (i = 0; i < j; i++) { - skb = tp->tx_skbuff[i] = saved_skb[i]; + skb = tp->tx_info[i].skb = saved_skb[i]; if ((long)skb->data & 3) { /* Must use alignment buffer. */ memcpy(tp->tx_buf[i], skb->data, skb->len); - outl(virt_to_bus(tp->tx_buf[i]), ioaddr + TxAddr0 + i*4); - } else - outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + i*4); + outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs), + ioaddr + TxAddr0 + i*4); + } else { + tp->tx_info[i].mapping = + pci_map_single(tp->pdev, skb->data, skb->len); + outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4); + } /* Note: the chip doesn't have auto-pad! */ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), ioaddr + TxStatus0 + i*4); } tp->cur_tx = i; - while (i < NUM_TX_DESC) - tp->tx_skbuff[i++] = 0; + while (i < NUM_TX_DESC) { + tp->tx_info[i].skb = NULL; + tp->tx_info[i].mapping = 0; + i++; + } if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ - dev->tbusy = 0; + netif_wake_queue(dev); tp->tx_full = 0; } else { tp->tx_full = 1; @@ -949,8 +971,9 @@ tp->dirty_tx = tp->cur_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { - tp->tx_skbuff[i] = 0; tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE]; + tp->tx_info[i].skb = NULL; + tp->tx_info[i].mapping = 0; } } @@ -961,29 +984,28 @@ long ioaddr = dev->base_addr; int entry; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start >= TX_TIMEOUT) - rtl8129_tx_timeout(dev); - return 1; - } + netif_stop_queue(dev); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - tp->tx_skbuff[entry] = skb; + tp->tx_info[entry].skb = skb; if ((long)skb->data & 3) { /* Must use alignment buffer. */ + tp->tx_info[entry].mapping = 0; memcpy(tp->tx_buf[entry], skb->data, skb->len); - outl(virt_to_bus(tp->tx_buf[entry]), ioaddr + TxAddr0 + entry*4); - } else - outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4); + outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs), + ioaddr + TxAddr0 + entry*4); + } else { + tp->tx_info[entry].mapping = + pci_map_single(tp->pdev, skb->data, skb->len); + outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4); + } /* Note: the chip doesn't have auto-pad! */ outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), ioaddr + TxStatus0 + entry*4); if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) { /* Typical path */ - clear_bit(0, (void*)&dev->tbusy); + netif_start_queue(dev); } else { tp->tx_full = 1; } @@ -1006,22 +1028,6 @@ int status, link_changed = 0; long ioaddr = dev->base_addr; -#if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } -#else - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif - do { status = inw(ioaddr + IntrStatus); /* Acknowledge all of the current interrupt sources ASAP, but @@ -1082,14 +1088,20 @@ tp->stats.tx_packets++; } + if (tp->tx_info[entry].mapping != 0) { + pci_unmap_single(tp->pdev, + tp->tx_info[entry].mapping, + tp->tx_info[entry].skb->len); + tp->tx_info[entry].mapping = 0; + } + /* Free the original skb. */ - dev_free_skb(tp->tx_skbuff[entry]); - tp->tx_skbuff[entry] = 0; + dev_free_skb(tp->tx_info[entry].skb); + tp->tx_info[entry].skb = NULL; if (tp->tx_full) { - /* The ring is no longer full, clear tbusy. */ + /* The ring is no longer full, wake the queue. */ tp->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue(dev); } dirty_tx++; } @@ -1162,12 +1174,6 @@ if (rtl8129_debug > 3) printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, inl(ioaddr + IntrStatus)); - -#if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); -#else - dev->interrupt = 0; -#endif return; } @@ -1289,8 +1295,7 @@ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (rtl8129_debug > 1) printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", @@ -1311,12 +1316,23 @@ free_irq(dev->irq, dev); for (i = 0; i < NUM_TX_DESC; i++) { - if (tp->tx_skbuff[i]) - dev_free_skb(tp->tx_skbuff[i]); - tp->tx_skbuff[i] = 0; + struct sk_buff *skb = tp->tx_info[i].skb; + dma_addr_t mapping = tp->tx_info[i].mapping; + + if (skb) { + if (mapping) + pci_unmap_single(tp->pdev, mapping, skb->len); + dev_free_skb(skb); + } + tp->tx_info[i].skb = NULL; + tp->tx_info[i].mapping = 0; } - kfree(tp->rx_ring); - kfree(tp->tx_bufs); + pci_free_consistent(tp->pdev, RX_BUF_LEN + 16, + tp->rx_ring, tp->rx_ring_dma); + pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC, + tp->tx_bufs, tp->tx_bufs_dma); + tp->rx_ring = NULL; + tp->tx_bufs = NULL; /* Green! Put the chip in low-power mode. */ outb(0xC0, ioaddr + Cfg9346); @@ -1356,7 +1372,7 @@ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; - if (dev->start) { + if (test_bit(LINK_STATE_START, &dev->state)) { tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); } diff -u --recursive --new-file v2.3.42/linux/drivers/net/setup.c linux/drivers/net/setup.c --- v2.3.42/linux/drivers/net/setup.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/setup.c Thu Feb 10 12:24:54 2000 @@ -8,7 +8,6 @@ #include #include -extern int plip_init(void); extern int mkiss_init_ctrl_dev(void); extern int ppp_init(void); extern int slip_init_ctrl_dev(void); @@ -21,42 +20,16 @@ extern int scc_init(void); extern int yam_init(void); -extern int acenic_probe(void); extern int awc4500_pci_probe(void); extern int awc4500_isa_probe(void); extern int awc4500_pnp_probe(void); extern int awc4500_365_probe(void); extern int arcnet_init(void); -extern int bigmac_probe(void); -extern int bmac_probe(void); extern int cpm_enet_init(void); -extern int oaknet_init(void); extern int dlci_setup(void); -extern int dgrs_probe(void); -extern int dmfe_reg_board(void); -extern int eepro100_probe(void); -extern int epic100_probe(void); -extern int happy_meal_probe(void); extern int lapbeth_init(void); -extern int mace_probe(void); -extern int myri_sbus_probe(void); -extern int ncr885e_probe(void); -extern int ne2k_pci_probe(void); -extern int pcnet32_probe(void); -extern int qec_probe(void); -extern int rcpci_probe(void); -extern int rr_hippi_probe(void); -extern int rtl8139_probe(void); extern int sdla_setup(void); extern int sdla_c_setup(void); -extern int sis900_probe(void); -extern int skge_probe(void); -extern int sparc_lance_probe(void); -extern int starfire_probe(void); -extern int tc59x_probe(void); -extern int tulip_probe(void); -extern int via_rhine_probe(void); -extern int yellowfin_probe(void); extern int abyss_probe(void); extern int madgemc_probe(void); @@ -104,9 +77,6 @@ #if defined(CONFIG_LAPBETHER) {lapbeth_init, 0}, #endif -#if defined(CONFIG_PLIP) - {plip_init, 0}, -#endif #if defined(CONFIG_ARCNET) {arcnet_init, 0}, #endif @@ -124,111 +94,6 @@ || (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP)) {slhc_install, 0}, #endif -#endif -/* - * HIPPI - */ -#ifdef CONFIG_ROADRUNNER - {rr_hippi_probe, 0}, -#endif - -/* - * ETHERNET - */ - -/* - * SBUS Ethernet - */ - -#ifdef CONFIG_HAPPYMEAL - {happy_meal_probe, 0}, -#endif -#ifdef CONFIG_SUNLANCE - {sparc_lance_probe, 0}, -#endif -#ifdef CONFIG_SUNQE - {qec_probe, 0}, -#endif -#ifdef CONFIG_SUNBMAC - {bigmac_probe, 0}, -#endif -#ifdef CONFIG_MYRI_SBUS - {myri_sbus_probe, 0}, -#endif - -/* - * PowerPC Mainboard - */ - -#ifdef CONFIG_MACE - {mace_probe, 0}, -#endif -#ifdef CONFIG_BMAC - {bmac_probe, 0}, -#endif -#ifdef CONFIG_NCR885E - {ncr885e_probe, 0}, -#endif - -/* - * IBM "Oak" Evaluation board - */ -#ifdef CONFIG_OAKNET - {oaknet_init, 0}, -#endif - -/* - * PCI Ethernet - */ -#ifdef CONFIG_DGRS - {dgrs_probe, 0}, -#endif -#ifdef CONFIG_RCPCI - {rcpci_probe, 0}, -#endif -#ifdef CONFIG_VORTEX - {tc59x_probe, 0}, -#endif -#ifdef CONFIG_NE2K_PCI - {ne2k_pci_probe, 0}, -#endif -#ifdef CONFIG_PCNET32 - {pcnet32_probe, 0}, -#endif -#ifdef CONFIG_EEXPRESS_PRO100 /* Intel EtherExpress Pro/100 */ - {eepro100_probe, 0}, -#endif -#ifdef CONFIG_DEC_ELCP - {tulip_probe, 0}, -#endif -#ifdef CONFIG_EPIC100 - {epic100_probe, 0}, -#endif -#ifdef CONFIG_RTL8139 - {rtl8139_probe, 0}, -#endif -#ifdef CONFIG_SIS900 - {sis900_probe, 0}, -#endif - -#ifdef CONFIG_DM9102 - {dmfe_reg_board, 0}, -#endif - -#ifdef CONFIG_YELLOWFIN - {yellowfin_probe, 0}, -#endif -#ifdef CONFIG_ACENIC - {acenic_probe, 0}, -#endif -#ifdef CONFIG_SK98LIN - {skge_probe, 0}, -#endif -#ifdef CONFIG_VIA_RHINE - {via_rhine_probe, 0}, -#endif -#ifdef CONFIG_ADAPTEC_STARFIRE - {starfire_probe, 0}, #endif /* diff -u --recursive --new-file v2.3.42/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.3.42/linux/drivers/net/shaper.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/shaper.c Wed Feb 9 20:08:09 2000 @@ -287,6 +287,7 @@ { struct shaper *sh=(struct shaper *)data; shaper_kick(sh); + timer_exit(&sh->timer); } /* @@ -404,9 +405,7 @@ { struct shaper *shaper=dev->priv; shaper_flush(shaper); - start_bh_atomic(); - del_timer(&shaper->timer); - end_bh_atomic(); + del_timer_sync(&shaper->timer); MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.3.42/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.3.42/linux/drivers/net/sis900.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/net/sis900.c Thu Feb 10 12:26:47 2000 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -112,6 +113,8 @@ struct net_device *next_module; struct net_device_stats stats; struct pci_dev * pci_dev; + + spinlock_t lock; struct mac_chip_info * mac; struct mii_phy * mii; @@ -131,15 +134,11 @@ int LinkOn; }; -#ifdef MODULE -#if LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Jim Huang "); MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver"); MODULE_PARM(multicast_filter_limit, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(debug, "i"); -#endif -#endif static int sis900_open(struct net_device *net_dev); static int sis900_mii_probe (struct net_device * net_dev); @@ -167,18 +166,16 @@ static struct net_device *root_sis900_dev = NULL; /* walk through every ethernet PCI devices to see if some of them are matched with our card list*/ -int sis900_probe (struct net_device * net_dev) +static int __init sis900_probe (void) { int found = 0; struct pci_dev * pci_dev = NULL; - if (!pci_present()) - return -ENODEV; - while ((pci_dev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_dev)) != NULL) { /* pci_dev contains all ethernet devices */ u32 pci_io_base; struct mac_chip_info * mac; + struct net_device *net_dev = NULL; for (mac = mac_chip_table; mac->vendor_id; mac++) { /* try to match our card list */ @@ -198,6 +195,7 @@ continue; /* setup various bits in PCI command register */ + pci_enable_device (pci_dev); pci_set_master(pci_dev); /* do the real low level jobs */ @@ -258,6 +256,7 @@ net_dev->irq = irq; sis_priv->pci_dev = pci_dev; sis_priv->mac = mac; + sis_priv->lock = SPIN_LOCK_UNLOCKED; /* probe for mii transciver */ if (sis900_mii_probe(net_dev) == 0) { @@ -277,6 +276,8 @@ net_dev->get_stats = &sis900_get_stats; net_dev->set_multicast_list = &set_rx_mode; net_dev->do_ioctl = &mii_ioctl; + net_dev->tx_timeout = sis900_tx_timeout; + net_dev->watchdog_timeo = TX_TIMEOUT; return net_dev; } @@ -506,9 +507,7 @@ set_rx_mode(net_dev); - net_dev->tbusy = 0; - net_dev->interrupt = 0; - net_dev->start = 1; + netif_start_queue(net_dev); /* Enable all known interrupts by setting the interrupt mask. */ outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr); @@ -811,7 +810,8 @@ } net_dev->trans_start = jiffies; - net_dev->tbusy = sis_priv->tx_full = 0; + sis_priv->tx_full = 0; + netif_start_queue(net_dev); /* FIXME: Should we restart the transmission thread here ?? */ @@ -827,13 +827,6 @@ long ioaddr = net_dev->base_addr; unsigned int entry; - /* test tbusy to see if we have timeout situation then set it */ - if (test_and_set_bit(0, (void*)&net_dev->tbusy) != 0) { - if (jiffies - net_dev->trans_start > TX_TIMEOUT) - sis900_tx_timeout(net_dev); - return 1; - } - /* Calculate the next Tx descriptor entry. */ entry = sis_priv->cur_tx % NUM_TX_DESC; sis_priv->tx_skbuff[entry] = skb; @@ -846,7 +839,7 @@ if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) { /* Typical path, clear tbusy to indicate more transmission is possible */ - clear_bit(0, (void*)&net_dev->tbusy); + netif_start_queue(net_dev); } else { /* no more transmit descriptor avaiable, tbusy remain set */ sis_priv->tx_full = 1; @@ -867,26 +860,12 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *net_dev = (struct net_device *)dev_instance; + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; int boguscnt = max_interrupt_work; long ioaddr = net_dev->base_addr; u32 status; -#if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&net_dev->interrupt)) { - printk(KERN_INFO "%s: SMP simultaneous entry of " - "an interrupt handler.\n", net_dev->name); - net_dev->interrupt = 0; /* Avoid halting machine. */ - return; - } -#else - if (net_dev->interrupt) { - printk(KERN_INFO "%s: Re-entering the interrupt handler.\n", - net_dev->name); - return; - } - net_dev->interrupt = 1; -#endif + spin_lock (&sis_priv->lock); do { status = inl(ioaddr + isr); @@ -923,11 +902,7 @@ "interrupt status = 0x%#8.8x.\n", net_dev->name, inl(ioaddr + isr)); -#if defined(__i386__) - clear_bit(0, (void*)&net_dev->interrupt); -#else - net_dev->interrupt = 0; -#endif + spin_unlock (&sis_priv->lock); return; } @@ -1079,13 +1054,12 @@ sis_priv->tx_ring[entry].cmdsts = 0; } - if (sis_priv->tx_full && net_dev->tbusy && + if (sis_priv->tx_full && test_bit(LINK_STATE_XOFF, &net_dev->flags) && sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { /* The ring is no longer full, clear tbusy, tx_full and schedule more transmission by marking NET_BH */ sis_priv->tx_full = 0; - clear_bit(0, (void *)&net_dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (net_dev); } } @@ -1096,8 +1070,7 @@ struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; int i; - net_dev->start = 0; - net_dev->tbusy = 1; + netif_stop_queue(net_dev); /* Disable interrupts by clearing the interrupt mask. */ outl(0x0000, ioaddr + imr); @@ -1264,14 +1237,7 @@ outl(PESEL, ioaddr + cfg); } -#ifdef MODULE -int init_module(void) -{ - return sis900_probe(NULL); -} - -void -cleanup_module(void) +static void __exit sis900_cleanup_module(void) { /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_sis900_dev) { @@ -1289,4 +1255,5 @@ } } -#endif /* MODULE */ +module_init(sis900_probe); +module_exit(sis900_cleanup_module); diff -u --recursive --new-file v2.3.42/linux/drivers/net/sk98lin/h/skdrv2nd.h linux/drivers/net/sk98lin/h/skdrv2nd.h --- v2.3.42/linux/drivers/net/sk98lin/h/skdrv2nd.h Tue Nov 23 22:42:20 1999 +++ linux/drivers/net/sk98lin/h/skdrv2nd.h Tue Feb 8 18:58:25 2000 @@ -429,6 +429,8 @@ caddr_t pDescrMem; /* Pointer to the descriptor area */ + dma_addr_t pDescrMemDMA; /* PCI DMA address of area */ + /* the port structures with descriptor rings */ TX_PORT TxPort[SK_MAX_MACS][2]; RX_PORT RxPort[SK_MAX_MACS]; diff -u --recursive --new-file v2.3.42/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c --- v2.3.42/linux/drivers/net/sk98lin/skge.c Tue Dec 7 09:32:44 1999 +++ linux/drivers/net/sk98lin/skge.c Thu Feb 10 12:26:47 2000 @@ -228,6 +228,7 @@ "@(#)SK-BUILD: 3.02 (19991111) PL: 01"; #include +#include #include "h/skdrv1st.h" #include "h/skdrv2nd.h" @@ -341,13 +342,14 @@ * 0, if everything is ok * !=0, on error */ -int __init skge_probe (struct net_device *dev) +static int __init skge_probe (void) { -int boards_found = 0; -int version_disp = 0; -SK_AC *pAC; -struct pci_dev *pdev = NULL; -unsigned long base_address; + int boards_found = 0; + int version_disp = 0; + SK_AC *pAC; + struct pci_dev *pdev = NULL; + unsigned long base_address; + struct net_device *dev = NULL; if (probed) return -ENODEV; @@ -375,21 +377,12 @@ } dev = init_etherdev(dev, sizeof(SK_AC)); - if (dev == NULL){ + if (dev == NULL || dev->priv == NULL){ printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); break; } - if (!dev->priv) - dev->priv = kmalloc(sizeof(SK_AC), GFP_KERNEL); - if (dev->priv == NULL){ - printk(KERN_ERR "Unable to allocate adapter " - "structure!\n"); - break; - } - - memset(dev->priv, 0, sizeof(SK_AC)); pAC = dev->priv; @@ -471,14 +464,7 @@ * or more boards. Otherwise, return failure (-ENODEV). */ -#ifdef MODULE return boards_found; -#else - if (boards_found > 0) - return 0; - else - return -ENODEV; -#endif } /* skge_probe */ @@ -515,8 +501,6 @@ } /* FreeResources */ -#ifdef MODULE - MODULE_AUTHOR("Christoph Goos "); MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver"); MODULE_PARM(AutoNeg_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); @@ -533,8 +517,6 @@ MODULE_PARM(options, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "i"); MODULE_PARM(debug, "i"); -#endif // MODULE - #ifdef AUTO_NEG_A static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A; @@ -597,15 +579,13 @@ #endif -#ifdef MODULE - static int debug = 0; /* not used */ static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */ /***************************************************************************** * - * init_module - module initialization function + * skge_init_module - module initialization function * * Description: * Very simple, only call skge_probe and return approriate result. @@ -614,9 +594,9 @@ * 0, if everything is ok * !=0, on error */ -int init_module(void) +static int __init skge_init_module(void) { -int cards; + int cards; root_dev = NULL; @@ -624,17 +604,17 @@ debug = 0; options[0] = 0; - cards = skge_probe(NULL); + cards = skge_probe(); if (cards == 0) { printk("No adapter found\n"); } return cards ? 0 : -ENODEV; -} /* init_module */ +} /* skge_init_module */ /***************************************************************************** * - * cleanup_module - module unload function + * skge_cleanup_module - module unload function * * Description: * Disable adapter if it is still running, free resources, @@ -642,7 +622,7 @@ * * Returns: N/A */ -void cleanup_module(void) +static void __exit skge_cleanup_module(void) { SK_AC *pAC; struct net_device *next; @@ -653,7 +633,7 @@ pAC = (SK_AC*)root_dev->priv; next = pAC->Next; - root_dev->tbusy = 1; + netif_stop_queue(root_dev); SkGeYellowLED(pAC, pAC->IoBase, 0); if(pAC->BoardLevel == 2) { @@ -687,9 +667,10 @@ root_dev = next; } -} -#endif /* cleanup_module */ +} /* skge_cleanup_module */ +module_init(skge_init_module); +module_exit(skge_cleanup_module); /***************************************************************************** * @@ -851,41 +832,35 @@ AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + RX_RING_SIZE + 8; #endif - pDescrMem = kmalloc(AllocLength, GFP_KERNEL); + pDescrMem = pci_alloc_consistent(&pAC->PciDev, AllocLength, + &pAC->pDescrMemDMA); if (pDescrMem == NULL) { return (SK_FALSE); } pAC->pDescrMem = pDescrMem; - memset(pDescrMem, 0, AllocLength); - /* Descriptors need 8 byte alignment */ - BusAddr = virt_to_bus(pDescrMem); - if (BusAddr & (DESCR_ALIGN-1)) { - pDescrMem += DESCR_ALIGN - (BusAddr & (DESCR_ALIGN-1)); - } + + /* Descriptors need 8 byte alignment, and this is ensured + * by pci_alloc_consistent. + */ + BusAddr = (unsigned long) pAC->pDescrMemDMA; for (i=0; iGIni.GIMacsFound; i++) { - if ((virt_to_bus(pDescrMem) & ~0xFFFFFFFFULL) != - (virt_to_bus(pDescrMem+TX_RING_SIZE) & ~0xFFFFFFFFULL)) { - pDescrMem += TX_RING_SIZE; - } SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("TX%d/A: pDescrMem: %lX, PhysDescrMem: %lX\n", i, (unsigned long) pDescrMem, - (unsigned long)virt_to_bus(pDescrMem))); + BusAddr)); pAC->TxPort[i][0].pTxDescrRing = pDescrMem; - pAC->TxPort[i][0].VTxDescrRing = virt_to_bus(pDescrMem); + pAC->TxPort[i][0].VTxDescrRing = BusAddr; pDescrMem += TX_RING_SIZE; + BusAddr += TX_RING_SIZE; - if ((virt_to_bus(pDescrMem) & ~0xFFFFFFFFULL) != - (virt_to_bus(pDescrMem+RX_RING_SIZE) & ~0xFFFFFFFFULL)) { - pDescrMem += RX_RING_SIZE; - } SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("RX%d: pDescrMem: %lX, PhysDescrMem: %lX\n", i, (unsigned long) pDescrMem, - (unsigned long)(virt_to_bus(pDescrMem)))); + (unsigned long)BusAddr)); pAC->RxPort[i].pRxDescrRing = pDescrMem; - pAC->RxPort[i].VRxDescrRing = virt_to_bus(pDescrMem); + pAC->RxPort[i].VRxDescrRing = BusAddr; pDescrMem += RX_RING_SIZE; + BusAddr += RX_RING_SIZE; } /* for */ return (SK_TRUE); @@ -905,9 +880,19 @@ static void BoardFreeMem( SK_AC *pAC) { +size_t AllocLength; /* length of complete descriptor area */ + SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("BoardFreeMem\n")); - kfree(pAC->pDescrMem); +#if (BITS_PER_LONG == 32) + AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8; +#else + AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + + RX_RING_SIZE + 8; +#endif + pci_free_consistent(&pAC->PciDev, AllocLength, + pAC->pDescrMem, pAC->pDescrMemDMA); + pAC->pDescrMem = NULL; } /* BoardFreeMem */ @@ -1428,10 +1413,6 @@ SkEventDispatcher(pAC, pAC->IoBase); spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - MOD_INC_USE_COUNT; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, @@ -1460,9 +1441,8 @@ int i; SK_EVPARA EvPara; - dev->start = 0; - set_bit(0, (void*)&dev->tbusy); - + netif_stop_queue(dev); + pAC = (SK_AC*) dev->priv; SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, @@ -1529,8 +1509,10 @@ if (Rc == 0) { /* transmitter out of resources */ - set_bit(0, (void*) &dev->tbusy); - return (0); + netif_stop_queue(dev); + + /* give buffer ownership back to the queueing layer */ + return (1); } dev->trans_start = jiffies; return (0); @@ -1584,7 +1566,6 @@ SK_DBGCAT_DRV_TX_PROGRESS, ("XmitFrame failed\n")); /* this message can not be sent now */ - DEV_KFREE_SKB(pMessage); return (0); } } @@ -1603,7 +1584,9 @@ #endif /* set up descriptor and CONTROL dword */ - PhysAddr = virt_to_bus(pMessage->data); + PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev, + pMessage->data, + pMessage->len); pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pTxd->pMBuf = pMessage; @@ -1662,6 +1645,7 @@ TXD *pTxd; /* pointer to the checked descriptor */ TXD *pNewTail; /* pointer to 'end' of the ring */ SK_U32 Control; /* TBControl field of descriptor */ +SK_U64 PhysAddr; /* address of DMA mapping */ pNewTail = pTxPort->pTxdRingTail; pTxd = pNewTail; @@ -1680,17 +1664,23 @@ * freed ( -> ring completely free now). */ pTxPort->pTxdRingTail = pTxd; - pAC->dev->tbusy = 0; + netif_start_queue(pAC->dev); return; } if (Control & TX_CTRL_OWN_BMU) { pTxPort->pTxdRingTail = pTxd; if (pTxPort->TxdRingFree > 0) { - pAC->dev->tbusy = 0; + netif_start_queue(pAC->dev); } return; } + /* release the DMA mapping */ + PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32; + PhysAddr |= (SK_U64) pTxd->VDataLow; + pci_unmap_single(&pAC->PciDev, PhysAddr, + pTxd->pMBuf->len); + DEV_KFREE_SKB(pTxd->pMBuf); /* free message */ pTxPort->TxdRingFree++; pTxd->TBControl &= ~TX_CTRL_SOFTWARE; @@ -1767,7 +1757,9 @@ pRxPort->pRxdRingTail = pRxd->pNextRxd; pRxPort->RxdRingFree--; Length = pAC->RxBufSize; - PhysAddr = virt_to_bus(pMsgBlock->data); + PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev, + pMsgBlock->data, + pAC->RxBufSize - 2); pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pRxd->pMBuf = pMsgBlock; @@ -1845,6 +1837,8 @@ unsigned short Csum2; unsigned short Type; int Result; +SK_U64 PhysAddr; + rx_start: /* do forever; exit if RX_CTRL_OWN_BMU found */ @@ -1876,17 +1870,19 @@ /* * 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) { - /* use original skb */ - /* set length in message */ - skb_put(pMsg, FrameLength); - } - else { - /* alloc new skb and copy data */ + 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); eth_copy_and_sum(pNewMsg, pMsg->data, FrameLength, 0); ReQueueRxBuffer(pAC, pRxPort, pMsg, @@ -1894,7 +1890,20 @@ pMsg = pNewMsg; } } - else { + + /* + * 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; + + /* release the DMA mapping */ + pci_unmap_single(&pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2); + /* set length in message */ skb_put(pMsg, FrameLength); /* hardware checksum */ @@ -2045,6 +2054,13 @@ /* remove error frame */ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR, ("Schrottdescriptor, length: 0x%x\n", FrameLength)); + + /* release the DMA mapping */ + PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; + PhysAddr |= (SK_U64) pRxd->VDataLow; + pci_unmap_single(&pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2); DEV_KFREE_SKB(pRxd->pMBuf); pRxd->pMBuf = NULL; pRxPort->RxdRingFree++; @@ -2110,6 +2126,7 @@ { RXD *pRxd; /* pointer to the current descriptor */ unsigned int Flags; + SK_U64 PhysAddr; if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) { return; @@ -2118,6 +2135,11 @@ pRxd = pRxPort->pRxdRingHead; do { if (pRxd->pMBuf != NULL) { + PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; + PhysAddr |= (SK_U64) pRxd->VDataLow; + pci_unmap_single(&pAC->PciDev, + PhysAddr, + pAC->RxBufSize - 2); DEV_KFREE_SKB(pRxd->pMBuf); pRxd->pMBuf = NULL; } @@ -2254,7 +2276,7 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeSetMacAddr starts now...\n")); - if(dev->start) { + if(test_bit(LINK_STATE_START, &dev->state)) { return -EBUSY; } memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); @@ -2380,7 +2402,7 @@ spin_lock_irqsave( &pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags); } - pAC->dev->tbusy = 1; + netif_stop_queue(pAC->dev); /* * adjust number of rx buffers allocated @@ -2469,7 +2491,7 @@ } #endif - pAC->dev->tbusy = 0; + netif_start_queue(pAC->dev); for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) { spin_unlock_irqrestore( &pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags); diff -u --recursive --new-file v2.3.42/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.3.42/linux/drivers/net/sk_g16.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sk_g16.c Thu Feb 10 12:26:47 2000 @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -455,6 +456,8 @@ static SK_RAM *board; /* pointer to our memory mapped board components */ +static spinlock_t SK_lock = SPIN_LOCK_UNLOCKED; + /* Macros */ @@ -939,11 +942,7 @@ if (!(i = SK_lance_init(dev, 0))) /* LANCE init OK? */ { - - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); #ifdef SK_DEBUG @@ -979,7 +978,6 @@ PRINTK(("## %s: LANCE init failed: CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); - dev->start = 0; /* Device not ready */ return -EAGAIN; } @@ -1176,7 +1174,7 @@ struct priv *p = (struct priv *) dev->priv; struct tmd *tmdp; - if (dev->tbusy) + if (test_bit(LINK_STATE_XOFF, &dev->flags)) { /* if Transmitter more than 150ms busy -> time_out */ @@ -1190,7 +1188,7 @@ SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */ - dev->tbusy = 0; /* Clear Transmitter flag */ + netif_start_queue(dev); /* Clear Transmitter flag */ dev->trans_start = jiffies; /* Mark Start of transmission */ @@ -1205,12 +1203,10 @@ * This means check if we are already in. */ - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ - { - printk("%s: Transmitter access conflict.\n", dev->name); - } - else + netif_stop_queue (dev); + { + /* Evaluate Packet length */ short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; @@ -1248,11 +1244,13 @@ * We own next buffer and are ready to transmit, so * clear busy flag */ - dev->tbusy = 0; + netif_start_queue(dev); } p->stats.tx_bytes += skb->len; + } + dev_kfree_skb(skb); return 0; } /* End of SK_send_packet */ @@ -1290,16 +1288,10 @@ printk("SK_interrupt(): IRQ %d for unknown device.\n", irq); } - - if (dev->interrupt) - { - printk("%s: Re-entering the interrupt handler.\n", dev->name); - } + spin_lock (&SK_lock); csr0 = SK_read_reg(CSR0); /* store register for checking */ - dev->interrupt = 1; /* We are handling an interrupt */ - /* * Acknowledge all of the current interrupt sources, disable * Interrupts (INEA = 0) @@ -1329,7 +1321,7 @@ SK_write_reg(CSR0, CSR0_INEA); /* Enable Interrupts */ - dev->interrupt = 0; /* We are out */ + spin_unlock (&SK_lock); } /* End of SK_interrupt() */ @@ -1430,14 +1422,7 @@ * We mark transmitter not busy anymore, because now we have a free * transmit descriptor which can be filled by SK_send_packet and * afterwards sent by the LANCE - */ - - dev->tbusy = 0; - - /* - * mark_bh(NET_BH); - * This will cause net_bh() to run after this interrupt handler. - * + * * The function which do handle slow IRQ parts is do_bottom_half() * which runs at normal kernel priority, that means all interrupt are * enabled. (see kernel/irq.c) @@ -1450,7 +1435,7 @@ * - try to transmit something from the send queue */ - mark_bh(NET_BH); + netif_wake_queue(dev); } /* End of SK_txintr() */ @@ -1625,8 +1610,7 @@ PRINTK(("## %s: SK_close(). CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); - dev->tbusy = 1; /* Transmitter busy */ - dev->start = 0; /* Card down */ + netif_stop_queue(dev); /* Transmitter busy */ printk("%s: Shutting %s down CSR0 %#06x\n", dev->name, SK_NAME, (int) SK_read_reg(CSR0)); @@ -2005,9 +1989,6 @@ printk("## Device Name: %s Base Address: %#06lx IRQ: %d\n", dev->name, dev->base_addr, dev->irq); - printk("## FLAGS: start: %d tbusy: %ld int: %ld\n", - dev->start, dev->tbusy, dev->interrupt); - printk("## next device: %#08x init function: %#08x\n", (int) dev->next, (int) dev->init); } diff -u --recursive --new-file v2.3.42/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c --- v2.3.42/linux/drivers/net/skeleton.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/skeleton.c Wed Feb 9 20:08:09 2000 @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -83,10 +84,19 @@ /* The number of low I/O ports used by the ethercard. */ #define NETCARD_IO_EXTENT 32 +#define MY_TX_TIMEOUT ((400*HZ)/1000) + /* Information that need to be kept for each board. */ struct net_local { struct net_device_stats stats; long open_time; /* Useless example local info. */ + + /* 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; }; /* The station (ethernet) address prefix, used for IDing the board. */ @@ -106,6 +116,8 @@ static int net_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); +static void net_tx_timeout(struct net_device *dev); + /* Example routines you must write ;->. */ #define tx_done(dev) 1 @@ -157,6 +169,7 @@ */ static int __init netcard_probe1(struct net_device *dev, int ioaddr) { + struct net_local *np; static unsigned version_printed = 0; int i; @@ -282,6 +295,9 @@ memset(dev->priv, 0, sizeof(struct net_local)); + np = (struct net_local *)dev->priv; + spin_lock_init(&np->lock); + /* Grab the region so that no one else tries to probe our ioports. */ request_region(ioaddr, NETCARD_IO_EXTENT, cardname); @@ -291,12 +307,41 @@ dev->get_stats = net_get_stats; dev->set_multicast_list = &set_multicast_list; + dev->tx_timeout = &net_tx_timeout; + dev->watchdog_timeo = MY_TX_TIMEOUT; + /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); return 0; } +static void net_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 conflict" : "network cable problem"); + + /* Try to restart the adaptor. */ + chipset_init(dev, 1); + + np->stats.tx_errors++; + + /* If we have space available to accept new transmit + * requests, wake up the queueing layer. This would + * be the case if the chipset_init() call above just + * flushes out the tx queue and empties it. + * + * If instead, the tx queue is retained then the + * netif_wake_queue() call should be placed in the + * TX completion interrupt handler of the driver instead + * of here. + */ + if (!tx_full(dev)) + netif_wake_queue(dev); +} + /* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. @@ -308,7 +353,7 @@ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *np = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; /* * This is used if the interrupt line can turned off (shared). @@ -327,100 +372,155 @@ } /* Reset the hardware here. Don't forget to set the station address. */ - /*chipset_init(dev, 1);*/ + chipset_init(dev, 1); outb(0x00, ioaddr); - lp->open_time = jiffies; + np->open_time = jiffies; - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + /* We are now ready to accept transmit requeusts from + * the queueing layer of the networking. + */ + netif_start_queue(dev); MOD_INC_USE_COUNT; return 0; } +/* This will only be invoked if your driver is _not_ in XOFF state. + * What this means is that you need not check it, and that this + * invariant will hold if you make sure that the netif_*_queue() + * calls are done at the proper times. + */ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *np = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; - if (dev->tbusy) { - /* - * If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) - return 1; - printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, - tx_done(dev) ? "IRQ conflict" : "network cable problem"); - /* Try to restart the adaptor. */ - chipset_init(dev, 1); - dev->tbusy=0; - dev->trans_start = jiffies; - } + /* If some error occurs while trying to transmit this + * packet, you should return '1' from this function. + * In such a case you _may not_ do anything to the + * SKB, it is still owned by the network queueing + * layer when an error is returned. This means you + * may not modify any SKB fields, you may not free + * the SKB, etc. + */ - /* - * Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. +#if TX_RING + /* This is the most common case for modern hardware. + * The spinlock protects this code from the TX complete + * hardware interrupt handler. Queue flow control is + * thus managed under this lock as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; - lp->stats.tx_bytes+=skb->len; - hardware_send_packet(ioaddr, buf, length); - dev->trans_start = jiffies; - } - dev_kfree_skb (skb); + spin_lock_irq(&np->lock); + + add_to_tx_ring(np, skb, length); + dev->trans_start = jiffied; + + /* If we just used up the very last entry in the + * TX ring on this device, tell the queueing + * layer to send no more. + */ + if (tx_full(dev)) + netif_stop_queue(dev); + + /* When the TX completion hw interrupt arrives, this + * is when the transmit statistics are updated. + */ + + spin_unlock_irq(&np->lock); +#else + /* This is the case for older hardware which takes + * a single transmit buffer at a time, and it is + * just written to the device via PIO. + * + * No spin locking is needed since there is no TX complete + * event. If by chance your card does have a TX complete + * hardware IRQ then you may need to utilize np->lock here. + */ + hardware_send_packet(ioaddr, buf, length); + np->stats.tx_bytes += skb->len; + + dev->trans_start = jiffies; /* You might need to clean up and record Tx statistics here. */ if (inw(ioaddr) == /*RU*/81) - lp->stats.tx_aborted_errors++; + np->stats.tx_aborted_errors++; + dev_kfree_skb (skb); +#endif return 0; } +#if TX_RING +/* This handles TX complete events posted by the device + * via interrupts. + */ +void net_tx(struct net_device *dev) +{ + struct net_local *np = (struct net_local *)dev->priv; + int entry; + + /* This protects us from concurrent execution of + * our dev->hard_start_xmit function above. + */ + spin_lock(&np->lock); + + entry = np->tx_old; + while (tx_entry_is_sent(np, entry)) { + struct sk_buff *skb = np->skbs[entry]; + + np->stats.tx_bytes += skb->len; + dev_kfree_skb_irq (skb); + + entry = next_tx_entry(np, entry); + } + np->tx_old = entry; + + /* If we had stopped the queue due to a "tx full" + * condition, and space has now been made available, + * wake up the queue. + */ + if (test_bit(LINK_STATE_XOFF, &dev->state) && + ! tx_full(dev)) + netif_wake_queue(dev); + + spin_unlock(&np->lock); +} +#endif + /* * The typical workload of the driver: - * Handle the network interface interrupts. + * Handle the network interface interrupts. */ static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; - struct net_local *lp; - int ioaddr, status, boguscount = 0; - - if (dev == NULL) { - printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); - return; - } - dev->interrupt = 1; + struct net_local *np; + int ioaddr, status; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; - status = inw(ioaddr + 0); - do { - if (status /*& RX_INTR*/) { - /* Got a packet(s). */ - net_rx(dev); - } - if (status /*& TX_INTR*/) { - lp->stats.tx_packets++; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ - } - if (status /*& COUNTERS_INTR*/) { - /* Increment the appropriate 'localstats' field. */ - lp->stats.tx_window_errors++; - } - } while (++boguscount < 20) ; + np = (struct net_local *)dev->priv; + status = inw(ioaddr + 0); - dev->interrupt = 0; - return; + if (status & RX_INTR) { + /* Got a packet(s). */ + net_rx(dev); + } +#if TX_RING + if (status & TX_INTR) { + /* Transmit complete. */ + net_tx(dev); + np->stats.tx_packets++; + netif_wake_queue(dev); + } +#endif + if (status & COUNTERS_INTR) { + /* Increment the appropriate 'localstats' field. */ + np->stats.tx_window_errors++; + } } /* We have a good packet(s), get it/them out of the buffers. */ @@ -470,11 +570,6 @@ } } while (--boguscount); - /* - * If any worth-while packets have been received, dev_rint() - * has done a mark_bh(NET_BH) for us and will work on them - * when we get to the bottom-half routine. - */ return; } @@ -487,8 +582,7 @@ lp->open_time = 0; - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); /* Flush the Tx and disable Rx here. */ diff -u --recursive --new-file v2.3.42/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v2.3.42/linux/drivers/net/slip.c Thu Nov 11 20:11:42 1999 +++ linux/drivers/net/slip.c Wed Feb 9 20:08:09 2000 @@ -169,9 +169,9 @@ if (slcomp == NULL) goto err_exit; #endif - start_bh_atomic(); + spin_lock_bh(&sl->lock); if (sl->tty == NULL) { - end_bh_atomic(); + spin_unlock_bh(&sl->lock); err = -ENODEV; goto err_exit; } @@ -189,7 +189,7 @@ sl->xbits = 0; #endif #endif - end_bh_atomic(); + spin_unlock_bh(&sl->lock); err = 0; /* Cleanup */ @@ -268,7 +268,7 @@ goto done; } - start_bh_atomic(); + spin_lock_bh(&sl->lock); err = -ENODEV; if (sl->tty == NULL) @@ -304,7 +304,7 @@ err = 0; done_on_bh: - end_bh_atomic(); + spin_unlock_bh(&sl->lock); done: if (xbuff) @@ -323,9 +323,7 @@ static inline void sl_lock(struct slip *sl) { - if (test_and_set_bit(0, (void *) &sl->dev->tbusy)) { - printk("%s: trying to lock already locked device!\n", sl->dev->name); - } + netif_stop_queue(sl->dev); } @@ -333,9 +331,7 @@ static inline void sl_unlock(struct slip *sl) { - if (!test_and_clear_bit(0, (void *)&sl->dev->tbusy)) { - printk("%s: trying to unlock already unlocked device!\n", sl->dev->name); - } + netif_wake_queue(sl->dev); } /* Send one completely decapsulated IP datagram to the IP layer. */ @@ -453,7 +449,7 @@ struct slip *sl = (struct slip *) tty->disc_data; /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) { + if (!sl || sl->magic != SLIP_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state)) { return; } if (sl->xleft <= 0) { @@ -462,7 +458,6 @@ sl->tx_packets++; tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); sl_unlock(sl); - mark_bh(NET_BH); return; } @@ -471,40 +466,25 @@ sl->xhead += actual; } -/* Encapsulate an IP datagram and kick it into a TTY queue. */ -static int -sl_xmit(struct sk_buff *skb, struct net_device *dev) +static void sl_tx_timeout(struct net_device *dev) { struct slip *sl = (struct slip*)(dev->priv); - if (!dev->start) { - printk("%s: xmit call when iface is down\n", dev->name); - dev_kfree_skb(skb); - return 0; - } - if (sl->tty == NULL) { - dev_kfree_skb(skb); - return 0; - } + spin_lock(&sl->lock); + + if (test_bit(LINK_STATE_XOFF, &dev->state)) { + struct slip *sl = (struct slip*)(dev->priv); + + if (!test_bit(LINK_STATE_START, &dev->state)) + goto out; - /* - * If we are busy already- too bad. We ought to be able - * to queue things at this point, to allow for a little - * frame buffer. Oh well... - * ----------------------------------------------------- - * I hate queues in SLIP driver. May be it's efficient, - * but for me latency is more important. ;) - * So, no queues ! - * 14 Oct 1994 Dmitry Gorodchanin. - */ - if (dev->tbusy) { /* May be we must check transmitter timeout here ? * 14 Oct 1994 Dmitry Gorodchanin. */ #ifdef SL_CHECK_TRANSMIT if (jiffies - dev->trans_start < 20 * HZ) { /* 20 sec timeout not reached */ - return 1; + goto out; } printk("%s: transmit timed out, %s?\n", dev->name, (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ? @@ -512,19 +492,39 @@ sl->xleft = 0; sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); sl_unlock(sl); -#else - return 1; #endif } - /* We were not busy, so we are now... :-) */ - if (skb != NULL) - { - sl_lock(sl); - sl->tx_bytes+=skb->len; - sl_encaps(sl, skb->data, skb->len); +out: + spin_unlock(&sl->lock); +} + + +/* Encapsulate an IP datagram and kick it into a TTY queue. */ +static int +sl_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct slip *sl = (struct slip*)(dev->priv); + + spin_lock(&sl->lock); + if (!test_bit(LINK_STATE_START, &dev->state)) { + spin_unlock(&sl->lock); + printk("%s: xmit call when iface is down\n", dev->name); dev_kfree_skb(skb); + return 0; } + if (sl->tty == NULL) { + spin_unlock(&sl->lock); + dev_kfree_skb(skb); + return 0; + } + + sl_lock(sl); + sl->tx_bytes+=skb->len; + sl_encaps(sl, skb->data, skb->len); + spin_unlock(&sl->lock); + + dev_kfree_skb(skb); return 0; } @@ -540,16 +540,15 @@ { struct slip *sl = (struct slip*)(dev->priv); - start_bh_atomic(); + spin_lock_bh(&sl->lock); if (sl->tty) { /* TTY discipline is running. */ sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); } - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); sl->rcount = 0; sl->xleft = 0; - end_bh_atomic(); + spin_unlock_bh(&sl->lock); MOD_DEC_USE_COUNT; return 0; @@ -565,8 +564,7 @@ return -ENODEV; sl->flags &= (1 << SLF_INUSE); - dev->start = 1; - dev->tbusy = 0; + netif_start_queue(dev); MOD_INC_USE_COUNT; return 0; } @@ -634,6 +632,10 @@ dev->mtu = sl->mtu; dev->hard_start_xmit = sl_xmit; +#ifdef SL_CHECK_TRANSMIT + dev->tx_timeout = sl_tx_timeout; + dev->watchdog_timeo = 20*HZ; +#endif dev->open = sl_open; dev->stop = sl_close; dev->get_stats = sl_get_stats; @@ -676,7 +678,8 @@ { struct slip *sl = (struct slip *) tty->disc_data; - if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) + if (!sl || sl->magic != SLIP_MAGIC || + !test_bit(LINK_STATE_START, &sl->dev->state)) return; /* Read the characters out of the buffer */ @@ -800,6 +803,7 @@ /* Initialize channel control data */ sl->magic = SLIP_MAGIC; sl->dev = &slp->dev; + spin_lock_init(&sl->lock); sl->mode = SL_MODE_DEFAULT; sprintf(slp->if_name, "sl%d", i); slp->dev.name = slp->if_name; @@ -946,10 +950,8 @@ /* VSV = very important to remove timers */ #ifdef CONFIG_SLIP_SMART - if (sl->keepalive) - del_timer (&sl->keepalive_timer); - if (sl->outfill) - del_timer (&sl->outfill_timer); + del_timer_sync(&sl->keepalive_timer); + del_timer_sync(&sl->outfill_timer); #endif /* Count references from TTY module */ @@ -1182,20 +1184,18 @@ if (tmp > 255) /* max for unchar */ return -EINVAL; - start_bh_atomic(); + spin_lock_bh(&sl->lock); if (!sl->tty) { - end_bh_atomic(); + spin_unlock_bh(&sl->lock); return -ENODEV; } - if (sl->keepalive) - (void)del_timer (&sl->keepalive_timer); if ((sl->keepalive = (unchar) tmp) != 0) { - sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; - add_timer(&sl->keepalive_timer); + mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); set_bit(SLF_KEEPTEST, &sl->flags); - } - end_bh_atomic(); - + } else { + del_timer (&sl->keepalive_timer); + } + spin_unlock_bh(&sl->lock); return 0; case SIOCGKEEPALIVE: @@ -1208,19 +1208,18 @@ return -EFAULT; if (tmp > 255) /* max for unchar */ return -EINVAL; - start_bh_atomic(); + spin_lock_bh(&sl->lock); if (!sl->tty) { - end_bh_atomic(); + spin_unlock_bh(&sl->lock); return -ENODEV; } - if (sl->outfill) - (void)del_timer (&sl->outfill_timer); if ((sl->outfill = (unchar) tmp) != 0){ - sl->outfill_timer.expires=jiffies+sl->outfill*HZ; - add_timer(&sl->outfill_timer); + mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); set_bit(SLF_OUTWAIT, &sl->flags); + } else { + del_timer (&sl->outfill_timer); } - end_bh_atomic(); + spin_unlock_bh(&sl->lock); return 0; case SIOCGOUTFILL: @@ -1253,10 +1252,10 @@ if (sl == NULL) /* Allocation failed ?? */ return -ENODEV; - start_bh_atomic(); /* Hangup would kill us */ + spin_lock_bh(&sl->lock); if (!sl->tty) { - end_bh_atomic(); + spin_unlock_bh(&sl->lock); return -ENODEV; } @@ -1265,14 +1264,15 @@ /* max for unchar */ if (((unsigned int)((unsigned long)rq->ifr_data)) > 255) return -EINVAL; - if (sl->keepalive) - (void)del_timer (&sl->keepalive_timer); sl->keepalive = (unchar) ((unsigned long)rq->ifr_data); if (sl->keepalive != 0) { sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; - add_timer(&sl->keepalive_timer); + mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); set_bit(SLF_KEEPTEST, &sl->flags); - } + } else { + del_timer(&sl->keepalive_timer); + } + spin_unlock_bh(&sl->lock); break; case SIOCGKEEPALIVE: @@ -1282,12 +1282,11 @@ case SIOCSOUTFILL: if (((unsigned)((unsigned long)rq->ifr_data)) > 255) /* max for unchar */ return -EINVAL; - if (sl->outfill) - del_timer (&sl->outfill_timer); if ((sl->outfill = (unchar)((unsigned long) rq->ifr_data)) != 0){ - sl->outfill_timer.expires=jiffies+sl->outfill*HZ; - add_timer(&sl->outfill_timer); + mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); set_bit(SLF_OUTWAIT, &sl->flags); + } else { + del_timer (&sl->outfill_timer); } break; @@ -1300,7 +1299,7 @@ and opened by another process device. */ if (sl->tty != current->tty && sl->pid != current->pid) { - end_bh_atomic(); + spin_unlock_bh(&sl->lock); return -EPERM; } sl->leased = 0; @@ -1311,7 +1310,7 @@ case SIOCGLEASE: rq->ifr_data=(caddr_t)((unsigned long)sl->leased); }; - end_bh_atomic(); + spin_unlock_bh(&sl->lock); return 0; } #endif @@ -1399,15 +1398,19 @@ } busy = 0; - start_bh_atomic(); + local_bh_disable(); for (i = 0; i < slip_maxdev; i++) { struct slip_ctrl *slc = slip_ctrls[i]; - if (slc && slc->ctrl.tty) { + if (!slc) + continue; + spin_lock(&slc->ctrl.lock); + if (slc->ctrl.tty) { busy++; tty_hangup(slc->ctrl.tty); } + spin_unlock(&slc->ctrl.lock); } - end_bh_atomic(); + local_bh_enable(); } while (busy && jiffies - start < 1*HZ); busy = 0; @@ -1449,8 +1452,10 @@ { struct slip *sl=(struct slip *)sls; - if (sl==NULL || sl->tty == NULL) - return; + spin_lock(&sl->lock); + + if (sl->tty == NULL) + goto out; if(sl->outfill) { @@ -1463,7 +1468,7 @@ unsigned char s = END; #endif /* put END into tty queue. Is it right ??? */ - if (!test_bit(0, (void *) &sl->dev->tbusy)) + if (!test_bit(LINK_STATE_XOFF, &sl->dev->state)) { /* if device busy no outfill */ sl->tty->driver.write(sl->tty, 0, &s, 1); @@ -1471,18 +1476,22 @@ } else set_bit(SLF_OUTWAIT, &sl->flags); - (void)del_timer(&sl->outfill_timer); - sl->outfill_timer.expires=jiffies+sl->outfill*HZ; - add_timer(&sl->outfill_timer); + + mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); } +out: + spin_unlock(&sl->lock); + timer_exit(&sl->outfill_timer); } static void sl_keepalive(unsigned long sls) { struct slip *sl=(struct slip *)sls; - if (sl == NULL || sl->tty == NULL) - return; + spin_lock(&sl->lock); + + if (sl->tty == NULL) + goto out; if( sl->keepalive) { @@ -1494,13 +1503,17 @@ printk("%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name); tty_hangup(sl->tty); /* this must hangup tty & close slip */ /* I think we need not something else */ - return; + goto out; } else set_bit(SLF_KEEPTEST, &sl->flags); - sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; - add_timer(&sl->keepalive_timer); + + mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); } + +out: + spin_unlock(&sl->lock); + timer_exit(&sl->keepalive_timer); } #endif diff -u --recursive --new-file v2.3.42/linux/drivers/net/slip.h linux/drivers/net/slip.h --- v2.3.42/linux/drivers/net/slip.h Wed Aug 18 11:36:45 1999 +++ linux/drivers/net/slip.h Wed Feb 9 20:08:09 2000 @@ -52,7 +52,9 @@ /* Various fields. */ struct tty_struct *tty; /* ptr to TTY structure */ - struct net_device *dev; /* easy for intr handling */ + struct net_device *dev; /* easy for intr handling */ + spinlock_t lock; + #ifdef SL_INCLUDE_CSLIP struct slcompress *slcomp; /* for header compression */ unsigned char *cbuff; /* compression buffer */ diff -u --recursive --new-file v2.3.42/linux/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.3.42/linux/drivers/net/starfire.c Thu Nov 18 20:25:37 1999 +++ linux/drivers/net/starfire.c Thu Feb 10 12:26:47 2000 @@ -68,19 +68,8 @@ #error You must compile this driver with "-O". #endif -/* Include files, designed to support most kernel versions 2.0.0 and later. */ -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #include -#include #include #include #include @@ -92,6 +81,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -101,7 +91,6 @@ #define RUN_AT(x) (jiffies + (x)) -#ifdef MODULE MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); @@ -111,7 +100,6 @@ MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -#endif /* Theory of Operation @@ -212,11 +200,12 @@ const char *name; u16 vendor_id, device_id, device_id_mask, flags; int io_size; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); + struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); }; -static struct net_device *starfire_probe1(int pci_bus, int pci_devfn, long ioaddr, - int irq, int chp_idx, int fnd_cnt); +static struct net_device *starfire_probe1(struct pci_dev *pdev, int pci_bus, + int pci_devfn, long ioaddr, + int irq, int chp_idx, int fnd_cnt); #if 0 #define ADDR_64BITS 1 /* This chip uses 64 bit addresses. */ @@ -322,25 +311,35 @@ #endif }; +struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + struct netdev_private { /* Descriptor rings first for alignment. */ struct starfire_rx_desc *rx_ring; struct starfire_tx_desc *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; struct net_device *next_module; /* Link for devices of this type. */ const char *product_name; /* The addresses of rx/tx-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct ring_info rx_info[RX_RING_SIZE]; + struct ring_info tx_info[TX_RING_SIZE]; /* Pointers to completion queues (full pages). I should cache line pad..*/ u8 pad0[100]; struct rx_done_desc *rx_done_q; + dma_addr_t rx_done_q_dma; unsigned int rx_done; struct tx_done_report *tx_done_q; unsigned int tx_done; + dma_addr_t tx_done_q_dma; struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ /* Frequently used values: keep some adjacent for cache effect. */ int chip_id; + struct pci_dev *pdev; unsigned char pci_bus, pci_devfn; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_tx, dirty_tx; @@ -396,10 +395,8 @@ unsigned char pci_bus, pci_device_fn; struct net_device *dev; - if ( ! pcibios_present()) - return -ENODEV; - for (;pci_index < 0xff; pci_index++) { + struct pci_dev *pdev; u16 vendor, device, pci_command, new_command; int chip_idx, irq; long pciaddr; @@ -409,28 +406,24 @@ &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); + pdev = pci_find_slot (pci_bus, pci_device_fn); + if (!pdev) continue; + vendor = pdev->vendor; + device = pdev->device; for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) if (vendor == pci_tbl[chip_idx].vendor_id && (device & pci_tbl[chip_idx].device_id_mask) == pci_tbl[chip_idx].device_id) break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ + if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ continue; - { - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); - - pciaddr = pdev->resource[0].start; + pciaddr = pdev->resource[0].start; #if defined(ADDR_64BITS) && defined(__alpha__) - pciaddr |= ((long)pdev->base_address[1]) << 32; + pciaddr |= ((long)pdev->base_address[1]) << 32; #endif - irq = pdev->irq; - } + irq = pdev->irq; if (debug > 2) printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", @@ -446,30 +439,26 @@ continue; } - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); new_command = pci_command | (pci_tbl[chip_idx].flags & 7); if (pci_command != new_command) { printk(KERN_INFO " The PCI BIOS has not enabled the" " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); + pci_write_config_word(pdev, PCI_COMMAND, new_command); } - dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, ioaddr, + dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found); if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { u8 pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < min_pci_latency) { printk(KERN_INFO " PCI latency timer (CFLT) is " "unreasonably low at %d. Setting to %d clocks.\n", pci_latency, min_pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, min_pci_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency); } } cards_found++; @@ -478,21 +467,15 @@ return cards_found ? 0 : -ENODEV; } -int starfire_probe(void) -{ - if (pci_etherdev_probe(pci_tbl) < 0) - return -ENODEV; - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); - return 0; -} - - static struct net_device * -starfire_probe1(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_id, int card_idx) +starfire_probe1(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_id, int card_idx) { struct netdev_private *np; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; - struct net_device *dev = init_etherdev(NULL, sizeof(struct netdev_private)); + struct net_device *dev = init_etherdev(NULL, 0); + + if (!dev) + return NULL; printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr); @@ -525,6 +508,7 @@ np->next_module = root_net_dev; root_net_dev = dev; + np->pdev = pdev; np->pci_bus = pci_bus; np->pci_devfn = pci_devfn; np->chip_id = chip_id; @@ -549,6 +533,8 @@ /* The chip-specific entries in the device structure. */ dev->open = &netdev_open; dev->hard_start_xmit = &start_tx; + dev->tx_timeout = tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; dev->stop = &netdev_close; dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; @@ -617,16 +603,29 @@ dev->name, dev->irq); /* Allocate the various queues, failing gracefully. */ if (np->tx_done_q == 0) - np->tx_done_q = (struct tx_done_report *)get_free_page(GFP_KERNEL); + np->tx_done_q = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->tx_done_q_dma); if (np->rx_done_q == 0) - np->rx_done_q = (struct rx_done_desc *)get_free_page(GFP_KERNEL); + np->rx_done_q = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->rx_done_q_dma); if (np->tx_ring == 0) - np->tx_ring = (struct starfire_tx_desc *)get_free_page(GFP_KERNEL); + np->tx_ring = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->tx_ring_dma); if (np->rx_ring == 0) - np->rx_ring = (struct starfire_rx_desc *)get_free_page(GFP_KERNEL); + np->rx_ring = pci_alloc_consistent(np->pdev, PAGE_SIZE, &np->rx_ring_dma); if (np->tx_done_q == 0 || np->rx_done_q == 0 - || np->rx_ring == 0 || np->tx_ring == 0) + || np->rx_ring == 0 || np->tx_ring == 0) { + if (np->tx_done_q) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->tx_done_q, np->tx_done_q_dma); + if (np->rx_done_q) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->rx_done_q, np->rx_done_q_dma); + if (np->tx_ring) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->tx_ring, np->tx_ring_dma); + if (np->rx_ring) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->rx_ring, np->rx_ring_dma); return -ENOMEM; + } MOD_INC_USE_COUNT; @@ -638,18 +637,19 @@ writel(0x02000401, ioaddr + TxDescCtrl); #if defined(ADDR_64BITS) && defined(__alpha__) - writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxDescQHiAddr); - writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingHiAddr); + /* XXX We really need a 64-bit PCI dma interfaces too... -DaveM */ + writel(np->rx_ring_dma >> 32, ioaddr + RxDescQHiAddr); + writel(np->tx_ring_dma >> 32, ioaddr + TxRingHiAddr); #else writel(0, ioaddr + RxDescQHiAddr); writel(0, ioaddr + TxRingHiAddr); writel(0, ioaddr + CompletionHiAddr); #endif - writel(virt_to_bus(np->rx_ring), ioaddr + RxDescQAddr); - writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); + writel(np->rx_ring_dma, ioaddr + RxDescQAddr); + writel(np->tx_ring_dma, ioaddr + TxRingPtr); - writel(virt_to_bus(np->tx_done_q), ioaddr + TxCompletionAddr); - writel(virt_to_bus(np->rx_done_q), ioaddr + RxCompletionAddr); + writel(np->tx_done_q_dma, ioaddr + TxCompletionAddr); + writel(np->rx_done_q_dma, ioaddr + RxCompletionAddr); if (debug > 1) printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name); @@ -674,17 +674,12 @@ if (dev->if_port == 0) dev->if_port = np->default_port; - dev->tbusy = 0; - dev->interrupt = 0; - if (debug > 1) printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name); set_rx_mode(dev); check_duplex(dev, 1); - dev->start = 1; - /* Set the interrupt mask and enable PCI interrupts. */ writel(IntrRxDone | IntrRxEmpty | IntrRxPCIErr | IntrTxDone | IntrTxEmpty | IntrTxPCIErr | @@ -794,7 +789,7 @@ /* Trigger an immediate transmit demand. */ - dev->trans_start = jiffies; + netif_wake_queue(dev); np->stats.tx_errors++; return; } @@ -815,12 +810,13 @@ /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; + np->rx_info[i].skb = skb; if (skb == NULL) break; + np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz); skb->dev = dev; /* Mark as being used by this device. */ /* Grrr, we cannot offset to correctly align the IP header. */ - np->rx_ring[i].rxaddr = cpu_to_le32(virt_to_bus(skb->tail) | RxDescValid); + np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid); } writew(i-1, dev->base_addr + RxDescQIdx); np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -828,7 +824,8 @@ /* Clear the remainder of the Rx buffer ring. */ for ( ; i < RX_RING_SIZE; i++) { np->rx_ring[i].rxaddr = 0; - np->rx_skbuff[i] = 0; + np->rx_info[i].skb = NULL; + np->rx_info[i].mapping = 0; } /* Mark the last entry as wrapping the ring. */ np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing); @@ -840,7 +837,8 @@ } for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_skbuff[i] = 0; + np->tx_info[i].skb = NULL; + np->tx_info[i].mapping = 0; np->tx_ring[i].status = 0; } return; @@ -851,14 +849,7 @@ struct netdev_private *np = (struct netdev_private *)dev->priv; unsigned entry; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - tx_timeout(dev); - return 1; - } + netif_stop_queue(dev); /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -866,9 +857,11 @@ /* Calculate the next Tx descriptor entry. */ entry = np->cur_tx % TX_RING_SIZE; - np->tx_skbuff[entry] = skb; + np->tx_info[entry].skb = skb; + np->tx_info[entry].mapping = + pci_map_single(np->pdev, skb->data, skb->len); - np->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data)); + np->tx_ring[entry].addr = cpu_to_le32(np->tx_info[entry].mapping); /* Add |TxDescIntr to generate Tx-done interrupts. */ np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID); if (debug > 5) { @@ -893,7 +886,7 @@ if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) np->tx_full = 1; if (! np->tx_full) - clear_bit(0, (void*)&dev->tbusy); + netif_start_queue(dev); dev->trans_start = jiffies; if (debug > 4) { @@ -921,21 +914,6 @@ ioaddr = dev->base_addr; np = (struct netdev_private *)dev->priv; -#if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } -#else - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif do { u32 intr_status = readl(ioaddr + IntrClear); @@ -974,11 +952,19 @@ if ((tx_status & 0xe0000000) == 0xa0000000) { np->stats.tx_packets++; } else if ((tx_status & 0xe0000000) == 0x80000000) { + struct sk_buff *skb; u16 entry = tx_status; /* Implicit truncate */ entry >>= 3; + + skb = np->tx_info[entry].skb; + pci_unmap_single(np->pdev, + np->tx_info[entry].mapping, + skb->len); + /* Scavenge the descriptor. */ - dev_kfree_skb(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = 0; + kfree_skb(skb); + np->tx_info[entry].skb = NULL; + np->tx_info[entry].mapping = 0; np->dirty_tx++; } np->tx_done_q[np->tx_done].status = 0; @@ -987,10 +973,9 @@ writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2); } if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { - /* The ring is no longer full, clear tbusy. */ + /* The ring is no longer full, wake the queue. */ np->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue(dev); } /* Abnormal error summary/uncommon events handlers. */ @@ -1009,23 +994,6 @@ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, readl(ioaddr + IntrStatus)); -#ifndef final_version - /* Code that should never be run! Remove after testing.. */ - { - static int stopit = 10; - if (dev->start == 0 && --stopit < 0) { - printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", - dev->name); - free_irq(irq, dev); - } - } -#endif - -#if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); -#else - dev->interrupt = 0; -#endif return; } @@ -1074,23 +1042,24 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single(np->pdev, + np->rx_info[entry].mapping, + pkt_len); #if HAS_IP_COPYSUM /* Call copy + cksum if available. */ - eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail, pkt_len); #endif } else { - char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len); - np->rx_skbuff[entry] = NULL; -#ifndef final_version /* Remove after testing. */ - if (bus_to_virt(le32_to_cpu(np->rx_ring[entry].rxaddr) & ~3) != temp) - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in netdev_rx: %p vs. %p / %p.\n", - dev->name, bus_to_virt(le32_to_cpu(np->rx_ring[entry].rxaddr)), - skb->head, temp); -#endif + char *temp; + + pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz); + skb = np->rx_info[entry].skb; + temp = skb_put(skb, pkt_len); + np->rx_info[entry].skb = NULL; + np->rx_info[entry].mapping = 0; } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ @@ -1124,13 +1093,16 @@ for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { struct sk_buff *skb; int entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { + if (np->rx_info[entry].skb == NULL) { skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[entry] = skb; + np->rx_info[entry].skb = skb; if (skb == NULL) break; /* Better luck next round. */ + np->rx_info[entry].mapping = + pci_map_single(np->pdev, skb->tail, np->rx_buf_sz); skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[entry].rxaddr = cpu_to_le32(virt_to_bus(skb->tail) | RxDescValid); + np->rx_ring[entry].rxaddr = + cpu_to_le32(np->rx_info[entry].mapping | RxDescValid); } if (entry == RX_RING_SIZE - 1) np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing); @@ -1184,10 +1156,8 @@ /* We should lock this segment of code for SMP eventually, although the vulnerability window is very small and statistics are non-critical. */ -#if LINUX_VERSION_CODE > 0x20119 np->stats.tx_bytes = readl(ioaddr + 0x57010); np->stats.rx_bytes = readl(ioaddr + 0x57044); -#endif np->stats.tx_packets = readl(ioaddr + 0x57000); np->stats.tx_aborted_errors = readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028); @@ -1313,8 +1283,7 @@ struct netdev_private *np = (struct netdev_private *)dev->priv; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, status was Int %4.4x.\n", @@ -1333,14 +1302,14 @@ #ifdef __i386__ if (debug > 2) { printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", - (int)virt_to_bus(np->tx_ring)); + np->tx_ring_dma); for (i = 0; i < 8 /* TX_RING_SIZE */; i++) printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n", i, le32_to_cpu(np->tx_ring[i].status), le32_to_cpu(np->tx_ring[i].addr), le32_to_cpu(np->tx_done_q[i].status)); printk(KERN_DEBUG " Rx ring at %8.8x -> %p:\n", - (int)virt_to_bus(np->rx_ring), np->rx_done_q); + np->rx_ring_dma, np->rx_done_q); if (np->rx_done_q) for (i = 0; i < 8 /* RX_RING_SIZE */; i++) { printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n", @@ -1354,18 +1323,23 @@ /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ - if (np->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - np->rx_skbuff[i]->free = 1; -#endif - dev_kfree_skb(np->rx_skbuff[i]); + if (np->rx_info[i].skb != NULL) { + pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz); + kfree_skb(np->rx_info[i].skb); } - np->rx_skbuff[i] = 0; + np->rx_info[i].skb = NULL; + np->rx_info[i].mapping = 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; + struct sk_buff *skb = np->tx_info[i].skb; + if (skb != NULL) { + pci_unmap_single(np->pdev, + np->tx_info[i].mapping, + skb->len); + kfree_skb(skb); + } + np->tx_info[i].skb = NULL; + np->tx_info[i].mapping = 0; } MOD_DEC_USE_COUNT; @@ -1373,9 +1347,7 @@ return 0; } - -#ifdef MODULE -int init_module(void) +static int __init starfire_init_module (void) { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); @@ -1391,7 +1363,7 @@ #endif } -void cleanup_module(void) +static void __exit starfire_cleanup_module (void) { struct net_device *next_dev; @@ -1406,15 +1378,27 @@ next_dev = np->next_module; unregister_netdev(root_net_dev); iounmap((char *)root_net_dev->base_addr); - if (np->tx_done_q) free_page((long)np->tx_done_q); - if (np->rx_done_q) free_page((long)np->rx_done_q); + if (np->tx_done_q) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->tx_done_q, np->tx_done_q_dma); + if (np->rx_done_q) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->rx_done_q, np->rx_done_q_dma); + if (np->tx_ring) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->tx_ring, np->tx_ring_dma); + if (np->rx_ring) + pci_free_consistent(np->pdev, PAGE_SIZE, + np->rx_ring, np->rx_ring_dma); kfree(root_net_dev); root_net_dev = next_dev; } } -#endif /* MODULE */ - +module_init(starfire_init_module); +module_exit(starfire_cleanup_module); + + /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c --- v2.3.42/linux/drivers/net/sunbmac.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/sunbmac.c Thu Feb 10 12:26:47 2000 @@ -1,4 +1,4 @@ -/* $Id: sunbmac.c,v 1.13 2000/01/28 13:42:29 jj Exp $ +/* $Id: sunbmac.c,v 1.14 2000/02/09 11:15:35 davem Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -190,14 +190,20 @@ for (i = 0; i < RX_RING_SIZE; i++) { if (bp->rx_skbs[i] != NULL) { - dev_kfree_skb(bp->rx_skbs[i]); + if (in_irq()) + dev_kfree_skb_irq(bp->rx_skbs[i]); + else + dev_kfree_skb(bp->rx_skbs[i]); bp->rx_skbs[i] = NULL; } } for (i = 0; i < TX_RING_SIZE; i++) { if (bp->tx_skbs[i] != NULL) { - dev_kfree_skb(bp->tx_skbs[i]); + if (in_irq()) + dev_kfree_skb_irq(bp->tx_skbs[i]); + else + dev_kfree_skb(bp->tx_skbs[i]); bp->tx_skbs[i] = NULL; } } @@ -750,8 +756,12 @@ static void bigmac_tx(struct bigmac *bp) { struct be_txd *txbase = &bp->bmac_block->be_txd[0]; - int elem = bp->tx_old; + struct net_device *dev = bp->dev; + int elem; + + spin_lock(&bp->lock); + elem = bp->tx_old; DTX(("bigmac_tx: tx_old[%d] ", elem)); while (elem != bp->tx_new) { struct sk_buff *skb; @@ -770,12 +780,18 @@ DTX(("skb(%p) ", skb)); bp->tx_skbs[elem] = NULL; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); elem = NEXT_TX(elem); } DTX((" DONE, tx_old=%d\n", elem)); bp->tx_old = elem; + + if (test_bit(LINK_STATE_XOFF, &dev->state) && + TX_BUFFS_AVAIL(bp) > 0) + netif_wake_queue(bp->dev); + + spin_unlock(&bp->lock); } /* BigMAC receive complete service routines. */ @@ -874,8 +890,6 @@ bmac_status = sbus_readl(bp->creg + CREG_STAT); qec_status = sbus_readl(bp->gregs + GLOB_STAT); - bp->dev->interrupt = 1; - DIRQ(("qec_status=%08x bmac_status=%08x\n", qec_status, bmac_status)); if ((qec_status & (GLOB_STAT_ER | GLOB_STAT_BM)) || (bmac_status & CREG_STAT_ERRORS)) @@ -886,13 +900,6 @@ if (bmac_status & CREG_STAT_RXIRQ) bigmac_rx(bp); - - if (bp->dev->tbusy && (TX_BUFFS_AVAIL(bp) > 0)) { - bp->dev->tbusy = 0; - mark_bh(NET_BH); - } - - bp->dev->interrupt = 0; } static int bigmac_open(struct net_device *dev) @@ -928,55 +935,43 @@ return 0; } +static void bigmac_tx_timeout(struct net_device *dev) +{ + struct bigmac *bp = (struct bigmac *) dev->priv; + + bigmac_init(bp, 0); + netif_wake_queue(dev); +} + /* Put a packet on the wire. */ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bigmac *bp = (struct bigmac *) dev->priv; int len, entry; - - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - - if (tickssofar < 40) { - return 1; - } else { - printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); - bp->enet_stats.tx_errors++; - bigmac_init(bp, 0); - dev->tbusy = 0; - dev->trans_start = jiffies; - dev_kfree_skb(skb); - return 0; - } - } - - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { - printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name); - return 1; - } - - if (!TX_BUFFS_AVAIL(bp)) - return 1; + u32 mapping; len = skb->len; - entry = bp->tx_new; - DTX(("bigmac_start_xmit: len(%d) entry(%d)\n", len, entry)); + mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len); /* Avoid a race... */ + spin_lock_irq(&bp->lock); + entry = bp->tx_new; + DTX(("bigmac_start_xmit: len(%d) entry(%d)\n", len, entry)); bp->bmac_block->be_txd[entry].tx_flags = TXD_UPDATE; bp->tx_skbs[entry] = skb; - bp->bmac_block->be_txd[entry].tx_addr = - sbus_map_single(bp->bigmac_sdev, skb->data, len); + bp->bmac_block->be_txd[entry].tx_addr = mapping; bp->bmac_block->be_txd[entry].tx_flags = (TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH)); - dev->trans_start = jiffies; bp->tx_new = NEXT_TX(entry); + if (TX_BUFFS_AVAIL(bp) <= 0) + netif_stop_queue(dev); + spin_unlock_irq(&bp->lock); /* Get it going. */ sbus_writel(CREG_CTRL_TWAKEUP, bp->creg + CREG_CTRL); - if (TX_BUFFS_AVAIL(bp)) - dev->tbusy = 0; + + dev->trans_start = jiffies; return 0; } @@ -1084,6 +1079,8 @@ bp->qec_sdev = qec_sdev; bp->bigmac_sdev = qec_sdev->child; + spin_lock_init(&bp->lock); + /* All further failures we find return this. */ res = ENODEV; @@ -1194,6 +1191,9 @@ dev->get_stats = &bigmac_get_stats; dev->set_multicast_list = &bigmac_set_multicast; + dev->tx_timeout = &bigmac_tx_timeout; + dev->watchdog_timeo = 5*HZ; + /* Finish net device registration. */ dev->irq = bp->bigmac_sdev->irqs[0]; dev->dma = 0; @@ -1251,7 +1251,7 @@ return 1; } -int __init bigmac_probe(void) +static int __init bigmac_probe(void) { struct net_device *dev = NULL; struct sbus_bus *sbus; @@ -1259,6 +1259,10 @@ static int called = 0; int cards = 0, v; +#ifdef MODULE + root_bigmac_dev = NULL; +#endif + if (called) return ENODEV; called++; @@ -1280,18 +1284,9 @@ return 0; } -#ifdef MODULE - -int -init_module(void) -{ - root_bigmac_dev = NULL; - return bigmac_probe(); -} - -void -cleanup_module(void) +static void __exit bigmac_cleanup(void) { +#ifdef MODULE /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_bigmac_dev) { struct bigmac *bp = root_bigmac_dev; @@ -1310,6 +1305,8 @@ kfree(bp->dev); root_bigmac_dev = bp_nxt; } +#endif /* MODULE */ } -#endif /* MODULE */ +module_init(bigmac_probe); +module_exit(bigmac_cleanup); diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunbmac.h linux/drivers/net/sunbmac.h --- v2.3.42/linux/drivers/net/sunbmac.h Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/sunbmac.h Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: sunbmac.h,v 1.5 1999/09/21 14:36:26 davem Exp $ +/* $Id: sunbmac.h,v 1.6 2000/02/09 11:15:36 davem Exp $ * sunbmac.h: Defines for the Sun "Big MAC" 100baseT ethernet cards. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -309,6 +309,8 @@ unsigned long tregs; /* BigMAC Transceiver */ struct bmac_init_block *bmac_block; /* RX and TX descriptors */ __u32 bblock_dvma; /* RX and TX descriptors */ + + spinlock_t lock; struct sk_buff *rx_skbs[RX_RING_SIZE]; struct sk_buff *tx_skbs[TX_RING_SIZE]; diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.3.42/linux/drivers/net/sunhme.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/sunhme.c Thu Feb 10 12:26:47 2000 @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.85 2000/01/28 13:42:27 jj Exp $ +/* $Id: sunhme.c,v 1.86 2000/02/09 11:15:36 davem Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. @@ -1194,7 +1194,10 @@ rxd = &hp->happy_block->happy_meal_rxd[i]; dma_addr = hme_read_desc32(hp, &rxd->rx_addr); hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE); - dev_kfree_skb(skb); + if (in_irq()) + dev_kfree_skb_irq(skb); + else + dev_kfree_skb(skb); hp->rx_skbs[i] = NULL; } } @@ -1208,7 +1211,10 @@ txd = &hp->happy_block->happy_meal_txd[i]; dma_addr = hme_read_desc32(hp, &txd->tx_addr); hme_dma_unmap(hp, dma_addr, skb->len); - dev_kfree_skb(skb); + if (in_irq()) + dev_kfree_skb_irq(skb); + else + dev_kfree_skb(skb); hp->tx_skbs[i] = NULL; } } @@ -1871,8 +1877,12 @@ { struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; struct happy_meal_txd *this; - int elem = hp->tx_old; + struct net_device *dev = hp->dev; + int elem; + spin_lock(&hp->happy_lock); + + elem = hp->tx_old; TXD(("TX<")); while (elem != hp->tx_new) { struct sk_buff *skb; @@ -1889,13 +1899,19 @@ hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes += skb->len; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); hp->net_stats.tx_packets++; elem = NEXT_TX(elem); } hp->tx_old = elem; TXD((">")); + + if (test_bit(LINK_STATE_XOFF, &dev->state) && + TX_BUFFS_AVAIL(hp) > 0) + netif_wake_queue(dev); + + spin_unlock(&hp->happy_lock); } #ifdef RXDEBUG @@ -2020,14 +2036,10 @@ HMD(("happy_meal_interrupt: status=%08x ", happy_status)); - dev->interrupt = 1; - if (happy_status & GREG_STAT_ERRORS) { HMD(("ERRORS ")); - if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status)) { - dev->interrupt = 0; + if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status)) return; - } } if (happy_status & GREG_STAT_MIFIRQ) { @@ -2045,12 +2057,6 @@ happy_meal_rx(hp, dev); } - if (dev->tbusy && (TX_BUFFS_AVAIL(hp) > 0)) { - hp->dev->tbusy = 0; - mark_bh(NET_BH); - } - - dev->interrupt = 0; HMD(("done\n")); } @@ -2072,14 +2078,10 @@ GREG_STAT_RXTOHOST))) continue; - dev->interrupt = 1; - if (happy_status & GREG_STAT_ERRORS) { HMD(("ERRORS ")); - if (happy_meal_is_not_so_happy(hp, happy_status)) { - dev->interrupt=0; + if (happy_meal_is_not_so_happy(hp, happy_status)) break; - } } if (happy_status & GREG_STAT_MIFIRQ) { @@ -2096,12 +2098,6 @@ HMD(("RXTOHOST ")); happy_meal_rx(hp, dev); } - - if (dev->tbusy && (TX_BUFFS_AVAIL(hp) > 0)) { - hp->dev->tbusy = 0; - mark_bh(NET_BH); - } - dev->interrupt = 0; } HMD(("done\n")); } @@ -2161,50 +2157,46 @@ #define SXD(x) #endif +static void happy_meal_tx_timeout(struct net_device *dev) +{ + struct happy_meal *hp = (struct happy_meal *) dev->priv; + + printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + tx_dump_log(); + printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name, + hme_read32(hp, hp->gregs + GREG_STAT), + hme_read32(hp, hp->etxregs + ETX_CFG), + hme_read32(hp, hp->bigmacregs + BMAC_TXCFG)); + happy_meal_init(hp, 0); + netif_wake_queue(dev); +} + static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct happy_meal *hp = (struct happy_meal *) dev->priv; int len, entry; + u32 mapping; - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { - int tickssofar = jiffies - dev->trans_start; - - if (tickssofar >= 40) { - printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); - hp->net_stats.tx_errors++; - tx_dump_log(); - printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name, - hme_read32(hp, hp->gregs + GREG_STAT), - hme_read32(hp, hp->etxregs + ETX_CFG), - hme_read32(hp, hp->bigmacregs + BMAC_TXCFG)); - happy_meal_init(hp, 0); - dev->tbusy = 0; - dev->trans_start = jiffies; - } else - tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_TBUSY, 0); - return 1; - } - - if (!TX_BUFFS_AVAIL(hp)) { - tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0); - return 1; - } len = skb->len; - entry = hp->tx_new; + mapping = hme_dma_map(hp, skb->data, len); + + spin_lock_irq(&hp->happy_lock); + entry = hp->tx_new; SXD(("SX", len, entry)); hp->tx_skbs[entry] = skb; hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], (TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE)), - hme_dma_map(hp, skb->data, len)); + mapping); hp->tx_new = NEXT_TX(entry); + if (TX_BUFFS_AVAIL(hp) <= 0) + netif_stop_queue(dev); + + spin_unlock_irq(&hp->happy_lock); /* Get it going. */ - dev->trans_start = jiffies; hme_write32(hp, hp->etxregs + ETX_PENDING, ETX_TP_DMAWAKEUP); - - if (TX_BUFFS_AVAIL(hp)) - dev->tbusy = 0; + dev->trans_start = jiffies; tx_add_log(hp, TXLOG_ACTION_TXMIT, 0); return 0; @@ -2228,7 +2220,7 @@ u32 crc, poly = CRC_POLYNOMIAL_LE; /* Lock out others. */ - set_bit(0, (void *) &dev->tbusy); + netif_stop_queue(dev); if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); @@ -2272,7 +2264,7 @@ } /* Let us get going again. */ - dev->tbusy = 0; + netif_wake_queue(dev); } /* Ethtool support... */ @@ -2552,6 +2544,8 @@ hp->happy_dev = sdev; + spin_lock_init(&hp->happy_lock); + if (sdev->num_registers != 5) { printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n", sdev->num_registers); @@ -2637,6 +2631,8 @@ dev->hard_start_xmit = &happy_meal_start_xmit; dev->get_stats = &happy_meal_get_stats; dev->set_multicast_list = &happy_meal_set_multicast; + dev->tx_timeout = &happy_meal_tx_timeout; + dev->watchdog_timeo = 5*HZ; dev->do_ioctl = &happy_meal_ioctl; dev->irq = sdev->irqs[0]; @@ -2741,6 +2737,8 @@ hp->happy_dev = pdev; + spin_lock_init(&hp->happy_lock); + if (qp != NULL) { hp->qfe_parent = qp; hp->qfe_ent = qfe_slot; @@ -2912,12 +2910,16 @@ } #endif -int __init happy_meal_probe(void) +static int __init happy_meal_probe(void) { struct net_device *dev = NULL; static int called = 0; int cards; +#ifdef MODULE + root_happy_dev = NULL; +#endif + if (called) return ENODEV; called++; @@ -2936,18 +2938,10 @@ return 0; } -#ifdef MODULE -int -init_module(void) -{ - root_happy_dev = NULL; - return happy_meal_probe(); -} - -void -cleanup_module(void) +static void __exit cleanup_module(void) { +#ifdef MODULE /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (root_happy_dev) { struct happy_meal *hp = root_happy_dev; @@ -2978,6 +2972,8 @@ kfree(hp->dev); root_happy_dev = next; } +#endif /* MODULE */ } -#endif /* MODULE */ +module_init(happy_meal_probe); +module_exit(happy_meal_cleanup_module); diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h --- v2.3.42/linux/drivers/net/sunhme.h Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/sunhme.h Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: sunhme.h,v 1.28 1999/09/21 14:36:34 davem Exp $ +/* $Id: sunhme.h,v 1.29 2000/02/09 11:15:40 davem Exp $ * sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver. * Also known as the "Happy Meal". * @@ -509,6 +509,8 @@ /* This is either a sbus_dev or a pci_dev. */ void *happy_dev; + + spinlock_t happy_lock; struct sk_buff *rx_skbs[RX_RING_SIZE]; struct sk_buff *tx_skbs[TX_RING_SIZE]; diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.3.42/linux/drivers/net/sunlance.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/sunlance.c Thu Feb 10 12:26:47 2000 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.93 2000/01/28 13:42:31 jj Exp $ +/* $Id: sunlance.c,v 1.94 2000/02/09 11:15:40 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -240,6 +240,8 @@ unsigned long dregs; /* DMA controller regs. */ volatile struct lance_init_block *init_block; + spinlock_t lock; + int rx_new, tx_new; int rx_old, tx_old; @@ -317,7 +319,6 @@ } /* Setup the Lance Rx and Tx rings */ -/* Sets dev->tbusy */ static void lance_init_ring_dvma(struct net_device *dev) { struct lance_private *lp = (struct lance_private *) dev->priv; @@ -327,7 +328,7 @@ int i; /* Lock out other processes while setting up hardware */ - dev->tbusy = 1; + netif_stop_queue(dev); lp->rx_new = lp->tx_new = 0; lp->rx_old = lp->tx_old = 0; @@ -383,7 +384,7 @@ int i; /* Lock out other processes while setting up hardware */ - dev->tbusy = 1; + netif_stop_queue(dev); lp->rx_new = lp->tx_new = 0; lp->rx_old = lp->tx_old = 0; @@ -573,6 +574,8 @@ volatile struct lance_init_block *ib = lp->init_block; int i, j; + spin_lock(&lp->lock); + j = lp->tx_old; for (i = j; i != lp->tx_new; i = j) { volatile struct lance_tx_desc *td = &ib->btx_ring [i]; @@ -637,6 +640,12 @@ j = TX_NEXT(j); } lp->tx_old = j; + + if (test_bit(LINK_STATE_XOFF, &dev->state) && + TX_BUFFS_AVAIL > 0) + netif_wake_queue(dev); + + spin_unlock(&lp->lock); } static void lance_piocopy_to_skb(struct sk_buff *skb, volatile void *piobuf, int len) @@ -736,6 +745,8 @@ volatile struct lance_init_block *ib = lp->init_block; int i, j; + spin_lock(&lp->lock); + j = lp->tx_old; for (i = j; i != lp->tx_new; i = j) { volatile struct lance_tx_desc *td = &ib->btx_ring [i]; @@ -800,6 +811,12 @@ j = TX_NEXT(j); } lp->tx_old = j; + + if (test_bit(LINK_STATE_XOFF, &dev->state) && + TX_BUFFS_AVAIL > 0) + netif_wake_queue(dev); + + spin_unlock(&lp->lock); } static void lance_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -808,11 +825,6 @@ struct lance_private *lp = (struct lance_private *)dev->priv; int csr0; - if (dev->interrupt) - printk(KERN_ERR "%s: again", dev->name); - - dev->interrupt = 1; - sbus_writew(LE_CSR0, lp->lregs + RAP); csr0 = sbus_readw(lp->lregs + RDP); @@ -833,11 +845,6 @@ if (csr0 & LE_C0_TINT) lp->tx(dev); - if ((TX_BUFFS_AVAIL > 0) && dev->tbusy) { - dev->tbusy = 0; - mark_bh(NET_BH); - } - if (csr0 & LE_C0_BABL) lp->stats.tx_errors++; @@ -867,11 +874,10 @@ lp->init_ring(dev); load_csrs(lp); init_restart_lance(lp); - dev->tbusy = 0; + netif_wake_queue(dev); } sbus_writew(LE_C0_INEA, lp->lregs + RDP); - dev->interrupt = 0; } /* Build a fake network packet and send it to ourselves. */ @@ -953,9 +959,7 @@ lp->init_ring(dev); load_csrs(lp); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); status = init_restart_lance(lp); if (!status && lp->auto_select) { @@ -973,9 +977,8 @@ { struct lance_private *lp = (struct lance_private *) dev->priv; - dev->start = 0; - dev->tbusy = 1; - del_timer(&lp->multicast_timer); + netif_stop_queue(dev); + del_timer_sync(&lp->multicast_timer); STOP_LANCE(lp); @@ -1007,9 +1010,6 @@ lp->init_ring(dev); load_csrs(lp); dev->trans_start = jiffies; - dev->interrupt = 0; - dev->start = 1; - dev->tbusy = 0; status = init_restart_lance(lp); return status; } @@ -1108,40 +1108,30 @@ sbus_writeb(0, piobuf); } +static void lance_tx_timeout(struct net_device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + + printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", + dev->name, sbus_readw(lp->lregs + RDP)); + lance_reset(dev); + netif_wake_queue(dev); +} + static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct lance_private *lp = (struct lance_private *) dev->priv; volatile struct lance_init_block *ib = lp->init_block; - unsigned long flags; int entry, skblen, len; - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { - int tickssofar = jiffies - dev->trans_start; - - if (tickssofar < 100) - return 1; - - printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", - dev->name, sbus_readw(lp->lregs + RDP)); - lp->stats.tx_errors++; - lance_reset(dev); - - return 1; - } - skblen = skb->len; - save_and_cli(flags); - - if (!TX_BUFFS_AVAIL) { - restore_flags(flags); - return 1; - } - len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; lp->stats.tx_bytes += len; + spin_lock_irq(&lp->lock); + entry = lp->tx_new & TX_RING_MOD_MASK; if (lp->pio_buffer) { sbus_writew((-len) | 0xf000, &ib->btx_ring[entry].length); @@ -1161,21 +1151,22 @@ lp->tx_new = TX_NEXT(entry); + if (TX_BUFFS_AVAIL <= 0) + netif_stop_queue(dev); + + spin_unlock_irq(&lp->lock); + /* Kick the lance: transmit now */ sbus_writew(LE_C0_INEA | LE_C0_TDMD, lp->lregs + RDP); dev->trans_start = jiffies; dev_kfree_skb(skb); - if (TX_BUFFS_AVAIL) - dev->tbusy = 0; - /* Read back CSR to invalidate the E-Cache. * This is needed, because DMA_DSBL_WR_INV is set. */ if (lp->dregs) sbus_readw(lp->lregs + RDP); - restore_flags(flags); return 0; } @@ -1255,20 +1246,17 @@ volatile struct lance_init_block *ib = lp->init_block; u16 mode; - if (!dev->start) + if (!test_bit(LINK_STATE_START, &dev->state)) return; - if (test_and_set_bit(0, (void *)&dev->tbusy)) { - mod_timer(&lp->multicast_timer, jiffies + 2); - return; - } - if (lp->tx_old != lp->tx_new) { mod_timer(&lp->multicast_timer, jiffies + 4); - dev->tbusy = 0; + netif_wake_queue(dev); return; } + netif_stop_queue(dev); + STOP_LANCE(lp); lp->init_ring(dev); @@ -1292,8 +1280,14 @@ } load_csrs(lp); init_restart_lance(lp); - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); +} + +static void lance_set_multicast_retry(unsigned long _opaque) +{ + struct net_device *dev = (struct net_device *) _opaque; + + lance_set_multicast(dev); } static void lance_free_hwresources(struct lance_private *lp) @@ -1476,6 +1470,8 @@ dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; + dev->tx_timeout = &lance_tx_timeout; + dev->watchdog_timeo = 5*HZ; dev->get_stats = &lance_get_stats; dev->set_multicast_list = &lance_set_multicast; @@ -1491,8 +1487,7 @@ */ init_timer(&lp->multicast_timer); lp->multicast_timer.data = (unsigned long) dev; - lp->multicast_timer.function = - (void (*)(unsigned long)) &lance_set_multicast; + lp->multicast_timer.function = &lance_set_multicast_retry; #ifdef MODULE dev->ifindex = dev_new_index(); @@ -1524,11 +1519,15 @@ #include /* Find all the lance cards on the system and initialize them */ -int __init sparc_lance_probe(void) +static int __init sparc_lance_probe(void) { static struct sbus_dev sdev; static int called = 0; +#ifdef MODULE + root_lance_dev = NULL; +#endif + if (called) return ENODEV; called++; @@ -1546,7 +1545,7 @@ #else /* !CONFIG_SUN4 */ /* Find all the lance cards on the system and initialize them */ -int __init sparc_lance_probe(void) +static int __init sparc_lance_probe(void) { struct sbus_bus *bus; struct sbus_dev *sdev = 0; @@ -1555,6 +1554,10 @@ static int called = 0; int cards = 0, v; +#ifdef MODULE + root_lance_dev = NULL; +#endif + if (called) return ENODEV; called++; @@ -1592,18 +1595,9 @@ } #endif /* !CONFIG_SUN4 */ -#ifdef MODULE - -int -init_module(void) -{ - root_lance_dev = NULL; - return sparc_lance_probe(); -} - -void -cleanup_module(void) +static void __exit sparc_lance_cleanup(void) { +#ifdef MODULE struct lance_private *lp; while (root_lance_dev) { @@ -1614,6 +1608,8 @@ kfree(root_lance_dev->dev); root_lance_dev = lp; } +#endif /* MODULE */ } -#endif /* MODULE */ +module_init(sparc_lance_probe); +module_exit(sparc_lance_cleanup); diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.3.42/linux/drivers/net/sunqe.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/net/sunqe.c Thu Feb 10 12:29:58 2000 @@ -1,4 +1,4 @@ -/* $Id: sunqe.c,v 1.41 2000/01/28 13:42:30 jj Exp $ +/* $Id: sunqe.c,v 1.43 2000/02/09 21:11:19 davem Exp $ * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed @@ -455,6 +455,8 @@ printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", qep->dev->name); } +static void qe_tx_reclaim(struct sunqe *qep); + /* Interrupts for all QE's get filtered out via the QEC master controller, * so we just run through each qe and check to see who is signaling * and thus needs to be serviced. @@ -470,11 +472,8 @@ while (channel < 4) { if (qec_status & 0xf) { struct sunqe *qep = qecp->qes[channel]; - struct net_device *dev = qep->dev; u32 qe_status; - dev->interrupt = 1; - qe_status = sbus_readl(qep->qcregs + CREG_STAT); if (qe_status & CREG_STAT_ERRORS) { if (qe_is_bolixed(qep, qe_status)) @@ -482,8 +481,20 @@ } if (qe_status & CREG_STAT_RXIRQ) qe_rx(qep); + if (test_bit(LINK_STATE_XOFF, &qep->dev->state) && + (qe_status & CREG_STAT_TXIRQ)) { + spin_lock(&qep->lock); + qe_tx_reclaim(qep); + if (TX_BUFFS_AVAIL(qep) > 0) { + /* Wake net queue and return to + * lazy tx reclaim. + */ + netif_wake_queue(qep->dev); + sbus_writel(1, qep->qcregs + CREG_TIMASK); + } + spin_unlock(&qep->lock); + } next: - dev->interrupt = 0; } qec_status >>= 4; channel++; @@ -514,11 +525,12 @@ return 0; } -/* Reclaim TX'd frames from the ring. */ +/* Reclaim TX'd frames from the ring. This must always run under + * the IRQ protected qep->lock. + */ static void qe_tx_reclaim(struct sunqe *qep) { struct qe_txd *txbase = &qep->qe_block->qe_txd[0]; - struct net_device *dev = qep->dev; int elem = qep->tx_old; while (elem != qep->tx_new) { @@ -529,11 +541,31 @@ elem = NEXT_TX(elem); } qep->tx_old = elem; +} - if (dev->tbusy && (TX_BUFFS_AVAIL(qep) > 0)) { - dev->tbusy = 0; - mark_bh(NET_BH); - } +static void qe_tx_timeout(struct net_device *dev) +{ + struct sunqe *qep = (struct sunqe *) dev->priv; + int tx_full; + + spin_lock_irq(&qep->lock); + + /* Try to reclaim, if that frees up some tx + * entries, we're fine. + */ + qe_tx_reclaim(qep); + tx_full = TX_BUFFS_AVAIL(qep) <= 0; + + spin_unlock_irq(&qep->lock); + + if (! tx_full) + goto out; + + printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + qe_init(qep, 1); + +out: + netif_wake_queue(dev); } /* Get a packet queued to go onto the wire. */ @@ -545,19 +577,9 @@ unsigned char *txbuf; int len, entry; - qe_tx_reclaim(qep); - - if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { - long tickssofar = jiffies - dev->trans_start; + spin_lock_irq(&qep->lock); - if (tickssofar >= 40) { - printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); - qe_init(qep, 1); - dev->tbusy = 0; - dev->trans_start = jiffies; - } - return 1; - } + qe_tx_reclaim(qep); len = skb->len; entry = qep->tx_new; @@ -583,10 +605,18 @@ qep->net_stats.tx_packets++; qep->net_stats.tx_bytes += len; - dev_kfree_skb(skb); + if (TX_BUFFS_AVAIL(qep) <= 0) { + /* Halt the net queue and enable tx interrupts. + * When the tx queue empties the tx irq handler + * will wake up the queue and return us back to + * the lazy tx reclaim scheme. + */ + netif_stop_queue(dev); + sbus_writel(0, qep->qcregs + CREG_TIMASK); + } + spin_unlock_irq(&qep->lock); - if (TX_BUFFS_AVAIL(qep)) - dev->tbusy = 0; + dev_kfree_skb(skb); return 0; } @@ -611,7 +641,7 @@ u32 crc, poly = CRC_POLYNOMIAL_LE; /* Lock out others. */ - set_bit(0, (void *) &dev->tbusy); + netif_stop_queue(dev); if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { sbus_writeb(MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET, @@ -673,7 +703,7 @@ sbus_writeb(qep->mconfig, qep->mregs + MREGS_MCONFIG); /* Let us get going again. */ - dev->tbusy = 0; + netif_wake_queue(dev); } /* This is only called once at boot time for each card probed. */ @@ -722,6 +752,7 @@ qe_devs[0] = dev; qeps[0] = (struct sunqe *) dev->priv; qeps[0]->channel = 0; + spin_lock_init(&qeps[0]->lock); for (j = 0; j < 6; j++) qe_devs[0]->dev_addr[j] = idprom->id_ethaddr[j]; @@ -857,6 +888,8 @@ qe_devs[i]->hard_start_xmit = qe_start_xmit; qe_devs[i]->get_stats = qe_get_stats; qe_devs[i]->set_multicast_list = qe_set_multicast; + qe_devs[i]->tx_timeout = qe_tx_timeout; + qe_devs[i]->watchdog_timeo = 5*HZ; qe_devs[i]->irq = sdev->irqs[0]; qe_devs[i]->dma = 0; ether_setup(qe_devs[i]); @@ -953,7 +986,7 @@ return 1; } -int __init qec_probe(void) +static int __init qec_probe(void) { struct net_device *dev = NULL; struct sbus_bus *bus; @@ -961,6 +994,10 @@ static int called = 0; int cards = 0, v; +#ifdef MODULE + root_qec_dev = NULL; +#endif + if (called) return ENODEV; called++; @@ -982,18 +1019,9 @@ return 0; } -#ifdef MODULE - -int -init_module(void) -{ - root_qec_dev = NULL; - return qec_probe(); -} - -void -cleanup_module(void) +static void __exit qec_cleanup(void) { +#ifdef MODULE struct sunqec *next_qec; int i; @@ -1021,6 +1049,8 @@ kfree(root_qec_dev); root_qec_dev = next_qec; } +#endif /* MODULE */ } -#endif /* MODULE */ +module_init(qec_probe); +module_exit(qec_cleanup); diff -u --recursive --new-file v2.3.42/linux/drivers/net/sunqe.h linux/drivers/net/sunqe.h --- v2.3.42/linux/drivers/net/sunqe.h Wed Dec 29 13:13:16 1999 +++ linux/drivers/net/sunqe.h Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: sunqe.h,v 1.12 1999/09/21 14:36:44 davem Exp $ +/* $Id: sunqe.h,v 1.13 2000/02/09 11:15:42 davem Exp $ * sunqe.h: Definitions for the Sun QuadEthernet driver. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -335,6 +335,7 @@ unsigned long mregs; /* Per-channel MACE Registers */ struct qe_init_block *qe_block; /* RX and TX descriptors */ __u32 qblock_dvma; /* RX and TX descriptors */ + spinlock_t lock; /* Protects txfull state */ int rx_new, rx_old; /* RX ring extents */ int tx_new, tx_old; /* TX ring extents */ struct sunqe_buffers *buffers; /* CPU visible address. */ diff -u --recursive --new-file v2.3.42/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.3.42/linux/drivers/net/tlan.c Tue Jan 11 22:31:40 2000 +++ linux/drivers/net/tlan.c Thu Feb 10 12:26:47 2000 @@ -47,7 +47,20 @@ * overwrite timers like TLAN_TIMER_ACTIVITY * Patch from John Cagle . * - Fixed a few compiler warnings. - * + * + * v1.3 Feb 04, 2000 - Fixed the remaining HZ issues. + * - Removed call to pci_present(). + * - Removed SA_INTERRUPT flag from irq handler. + * - Added __init and __initdata to reduce resisdent + * code size. + * - Driver now uses module_init/module_exit. + * - Rewrote init_module and tlan_probe to + * share a lot more code. We now use tlan_probe + * with builtin and module driver. + * - Driver ported to new net API. + * - tlan.txt has been reworked to reflect current + * driver (almost) + * - Other minor stuff * *******************************************************************************/ @@ -56,6 +69,7 @@ #include "tlan.h" +#include #include #include #include @@ -66,35 +80,32 @@ typedef u32 (TLanIntVectorFunc)( struct net_device *, u16 ); -#ifdef MODULE static struct net_device *TLanDevices = NULL; static int TLanDevicesInstalled = 0; +/* Force speed, duplex and aui settings */ static int aui = 0; -static int sa_int = 0; -static int duplex = 0; +static int duplex = 0; static int speed = 0; MODULE_PARM(aui, "i"); -MODULE_PARM(sa_int, "i"); MODULE_PARM(duplex, "i"); MODULE_PARM(speed, "i"); MODULE_PARM(debug, "i"); EXPORT_NO_SYMBOLS; -#endif - - +/* Turn on debugging. See linux/Documentation/networking/tlan.txt for details */ static int debug = 0; + static int bbuf = 0; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; static int TLanVersionMajor = 1; -static int TLanVersionMinor = 2; +static int TLanVersionMinor = 3; -static TLanAdapterEntry TLanAdapterList[] = { +static TLanAdapterEntry TLanAdapterList[] __initdata = { { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10, "Compaq Netelligent 10 T PCI UTP", @@ -183,7 +194,7 @@ static int TLan_PciProbe( u8 *, u8 *, u8 *, u32 *, u32 * ); -static int TLan_Init( struct net_device * ); +static int TLan_Init( struct net_device * ); static int TLan_Open(struct net_device *dev); static int TLan_StartTx(struct sk_buff *, struct net_device *); static void TLan_HandleInterrupt(int, void *, struct pt_regs *); @@ -282,114 +293,9 @@ *****************************************************************************/ -#ifdef MODULE /*************************************************************** - * init_module - * - * Returns: - * 0 if module installed ok, non-zero if not. - * Parms: - * None - * - * This function begins the setup of the driver creating a - * pad buffer, finding all TLAN devices (matching - * TLanAdapterList entries), and creating and initializing a - * device structure for each adapter. - * - **************************************************************/ - -extern int init_module(void) -{ - TLanPrivateInfo *priv; - struct net_device *dev; - size_t dev_size; - u8 dfn; - u32 index; - int failed; - int found; - u32 io_base; - u8 irq; - u8 rev; - - printk( "TLAN driver, v%d.%d, (C) 1997-8 Caldera, Inc.\n", - TLanVersionMajor, - TLanVersionMinor - ); - TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, - ( GFP_KERNEL | GFP_DMA ) - ); - if ( TLanPadBuffer == NULL ) { - printk( "TLAN: Could not allocate memory for pad buffer.\n" ); - return -ENOMEM; - } - - memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); - - dev_size = sizeof(struct net_device) + sizeof(TLanPrivateInfo); - - while ( ( found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index ) ) ) { - dev = (struct net_device *) kmalloc( dev_size, GFP_KERNEL ); - if ( dev == NULL ) { - printk( "TLAN: Could not allocate memory for device.\n" ); - continue; - } - memset( dev, 0, dev_size ); - - dev->priv = priv = ( (void *) dev ) + sizeof(struct net_device); - dev->name = priv->devName; - strcpy( priv->devName, " " ); - dev->base_addr = io_base; - dev->irq = irq; - dev->init = TLan_Init; - - priv->adapter = &TLanAdapterList[index]; - priv->adapterRev = rev; - priv->aui = aui; - if ( ( duplex != 1 ) && ( duplex != 2 ) ) { - duplex = 0; - } - priv->duplex = duplex; - if ( ( speed != 10 ) && ( speed != 100 ) ) { - speed = 0; - } - priv->speed = speed; - priv->sa_int = sa_int; - priv->debug = debug; - - spin_lock_init(&priv->lock); - - ether_setup( dev ); - - failed = register_netdev( dev ); - - if ( failed ) { - printk( "TLAN: Could not register device.\n" ); - kfree( dev ); - } else { - priv->nextDevice = TLanDevices; - TLanDevices = dev; - TLanDevicesInstalled++; - printk("TLAN: %s irq=%2d io=%04x, %s, Rev. %d\n", - dev->name, - (int) dev->irq, - (int) dev->base_addr, - priv->adapter->deviceLabel, - priv->adapterRev ); - } - } - - /* printk( "TLAN: Found %d device(s).\n", TLanDevicesInstalled ); */ - - return ( ( TLanDevicesInstalled > 0 ) ? 0 : -ENODEV ); - -} /* init_module */ - - - - - /*************************************************************** - * cleanup_module + * tlan_exit * * Returns: * Nothing @@ -403,7 +309,8 @@ * **************************************************************/ -extern void cleanup_module(void) + +static void __exit tlan_exit(void) { struct net_device *dev; TLanPrivateInfo *priv; @@ -422,108 +329,111 @@ } kfree( TLanPadBuffer ); -} /* cleanup_module */ - - -#else /* MODULE */ +} - - - /*************************************************************** +/* + *************************************************************** * tlan_probe * * Returns: * 0 on success, error code on error - * Parms: - * dev device struct to use if adapter is - * found. + * Parms: + * none * * The name is lower case to fit in with all the rest of - * the netcard_probe names. This function looks for a/ + * the netcard_probe names. This function looks for * another TLan based adapter, setting it up with the - * provided device struct if one is found. + * allocated device struct if one is found. + * tlan_probe has been ported to the new net API and + * now allocates its own device structure. This function + * is also used by modules. * **************************************************************/ - -extern int tlan_probe( struct net_device *dev ) + +static int __init tlan_probe(void) { - TLanPrivateInfo *priv; - static int pad_allocated = 0; - int found; - u8 dfn, irq, rev; - u32 io_base, index; - found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index ); + struct net_device *dev; + TLanPrivateInfo *priv; + static int pad_allocated = 0; + u8 dfn, irq, rev; + u32 io_base, index; + int found; + + printk(KERN_INFO "ThunderLAN driver v%d.%d:\n", + TLanVersionMajor, + TLanVersionMinor); + + TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, + (GFP_KERNEL | GFP_DMA)); - if ( ! found ) { - return -ENODEV; + if (TLanPadBuffer == NULL) { + printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); + return -ENOMEM; } - dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL ); - - if ( dev->priv == NULL ) { - printk( "TLAN: Could not allocate memory for device.\n" ); - return -ENOMEM; - } + memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE); - memset( dev->priv, 0, sizeof(TLanPrivateInfo) ); - - if ( ! pad_allocated ) { - TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, -// ( GFP_KERNEL | GFP_DMA ) - ( GFP_KERNEL ) - ); - if ( TLanPadBuffer == NULL ) { - printk( "TLAN: Could not allocate memory for padding.\n" ); - kfree( dev->priv ); + while((found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index))) { + dev = init_etherdev(NULL, sizeof(TLanPrivateInfo)); + if (dev == NULL) { + printk(KERN_ERR "TLAN: Could not allocate memory for device.\n"); return -ENOMEM; - } else { - pad_allocated = 1; - memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); } - } - - priv = (TLanPrivateInfo *) dev->priv; - - dev = init_etherdev( dev, sizeof(TLanPrivateInfo) ); - - dev->base_addr = io_base; - dev->irq = irq; - + priv = dev->priv; + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(TLanPrivateInfo), GFP_KERNEL); + priv = dev->priv; + } + memset(priv, 0, sizeof(TLanPrivateInfo)); + + pad_allocated = 1; + + dev->base_addr = io_base; + dev->irq = irq; + priv->adapter = &TLanAdapterList[index]; + priv->adapterRev = rev; + priv->aui = aui; + + if ( ( duplex != 1 ) && ( duplex != 2 ) ) + duplex = 0; + priv->duplex = duplex; - priv->adapter = &TLanAdapterList[index]; - priv->adapterRev = rev; - priv->aui = dev->mem_start & 0x01; - priv->duplex = ( ( dev->mem_start & 0x0C ) == 0x0C ) ? 0 : ( dev->mem_start & 0x0C ) >> 2; - priv->speed = ( ( dev->mem_start & 0x30 ) == 0x30 ) ? 0 : ( dev->mem_start & 0x30 ) >> 4; - if ( priv->speed == 0x1 ) { - priv->speed = TLAN_SPEED_10; - } else if ( priv->speed == 0x2 ) { - priv->speed = TLAN_SPEED_100; - } - priv->sa_int = dev->mem_start & 0x02; - priv->debug = dev->mem_end; - spin_lock_init(&priv->lock); - - printk("TLAN %d.%d: %s irq=%2d io=%04x, %s, Rev. %d\n", - TLanVersionMajor, - TLanVersionMinor, - dev->name, - (int) irq, - io_base, - priv->adapter->deviceLabel, - priv->adapterRev ); + if ( ( speed != 10 ) && ( speed != 100 ) ) + speed = 0; - TLan_Init( dev ); + priv->speed = speed; + priv->debug = debug; + spin_lock_init(&priv->lock); + + if (TLan_Init(dev)) { + printk(KERN_ERR "TLAN: Could not register device.\n"); + unregister_netdev(dev); + kfree(dev); + } else { - return 0; - -} /* tlan_probe */ - + TLanDevicesInstalled++; + priv->nextDevice = TLanDevices; + TLanDevices = dev; + printk(KERN_INFO "TLAN: %s irq=%2d, io=%04x, %s, Rev. %d\n", + dev->name, + (int) dev->irq, + (int) dev->base_addr, + priv->adapter->deviceLabel, + priv->adapterRev); + } -#endif /* MODULE */ + } + + printk(KERN_INFO "TLAN: %d device(s) installed\n", TLanDevicesInstalled); + + return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV); +} +/* Module loading/unloading */ +module_init(tlan_probe); +module_exit(tlan_exit); @@ -559,11 +469,6 @@ int reg; - if ( ! pci_present() ) { - printk( "TLAN: PCI Bios not present.\n" ); - return 0; - } - for (; TLanAdapterList[dl_index].vendorId != 0; dl_index++) { pdev = pci_find_device( @@ -574,7 +479,7 @@ TLAN_DBG( TLAN_DEBUG_GNRL, - "TLAN: found: Vendor Id = 0x%hx, Device Id = 0x%hx\n", + "found: Vendor Id = 0x%hx, Device Id = 0x%hx\n", TLanAdapterList[dl_index].vendorId, TLanAdapterList[dl_index].deviceId ); @@ -589,7 +494,7 @@ pci_read_config_dword( pdev, reg, pci_io_base); if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pci_io_base); + TLAN_DBG( TLAN_DEBUG_GNRL, "IO mapping is available at %x.\n", *pci_io_base); break; } else { *pci_io_base = 0; @@ -597,7 +502,7 @@ } if ( *pci_io_base == 0 ) - printk("TLAN: IO mapping not available, ignoring device.\n"); + printk(KERN_INFO "TLAN: IO mapping not available, ignoring device.\n"); pci_set_master(pdev); @@ -635,7 +540,7 @@ * **************************************************************/ -int TLan_Init( struct net_device *dev ) +static int TLan_Init( struct net_device *dev ) { int dma_size; int err; @@ -643,17 +548,17 @@ TLanPrivateInfo *priv; priv = (TLanPrivateInfo *) dev->priv; - err = check_region( dev->base_addr, 0x10 ); if ( err ) { - printk( "TLAN: %s: Io port region 0x%lx size 0x%x in use.\n", + printk(KERN_ERR "TLAN: %s: Io port region 0x%lx size 0x%x in use.\n", dev->name, dev->base_addr, 0x10 ); return -EIO; } + request_region( dev->base_addr, 0x10, TLanSignature ); - + if ( bbuf ) { dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); @@ -661,10 +566,9 @@ dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) ); } - - priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA ); + priv->dmaStorage = kmalloc(dma_size, GFP_KERNEL | GFP_DMA); if ( priv->dmaStorage == NULL ) { - printk( "TLAN: Could not allocate lists and buffers for %s.\n", + printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n", dev->name ); return -ENOMEM; } @@ -672,7 +576,6 @@ priv->rxList = (TLanList *) ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; - if ( bbuf ) { priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); priv->txBuffer = priv->rxBuffer @@ -685,13 +588,13 @@ (u8) priv->adapter->addrOfs + i, (u8 *) &dev->dev_addr[i] ); if ( err ) { - printk( "TLAN: %s: Error reading MAC from eeprom: %d\n", + printk(KERN_ERR "TLAN: %s: Error reading MAC from eeprom: %d\n", dev->name, err ); } - dev->addr_len = 6; - + + /* Device methods */ dev->open = &TLan_Open; dev->hard_start_xmit = &TLan_StartTx; dev->stop = &TLan_Close; @@ -727,24 +630,18 @@ { TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; int err; - + + MOD_INC_USE_COUNT; + priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); - if ( priv->sa_int ) { - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Using SA_INTERRUPT\n" ); - err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ | SA_INTERRUPT, TLanSignature, dev ); - } else { - err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev ); - } + err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev ); + if ( err ) { - printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); + printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); return -EAGAIN; } - MOD_INC_USE_COUNT; - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); /* NOTE: It might not be necessary to read the stats before a reset if you don't care what the values are. @@ -753,7 +650,7 @@ TLan_ReadAndClearStats( dev, TLAN_IGNORE ); TLan_ResetAdapter( dev ); - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev ); return 0; @@ -792,7 +689,7 @@ unsigned long flags; if ( ! priv->phyOnline ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); dev_kfree_skb( skb ); return 0; } @@ -800,8 +697,8 @@ tail_list = priv->txList + priv->txTail; if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); - dev->tbusy = 1; + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); + netif_stop_queue(dev); priv->txBusyCount++; return 1; } @@ -835,11 +732,11 @@ if ( ! priv->txInProgress ) { priv->txInProgress = 1; outw( 0x4, dev->base_addr + TLAN_HOST_INT ); - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD ); } else { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); if ( priv->txTail == 0 ) { ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list ); } else { @@ -896,10 +793,6 @@ priv = (TLanPrivateInfo *) dev->priv; spin_lock(&priv->lock); - if ( dev->interrupt ) { - printk( "TLAN: Re-entering interrupt handler for %s: %ld.\n" , dev->name, dev->interrupt ); - } - dev->interrupt++; host_int = inw( dev->base_addr + TLAN_HOST_INT ); outw( host_int, dev->base_addr + TLAN_HOST_INT ); @@ -913,7 +806,6 @@ outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); } - dev->interrupt--; spin_unlock(&priv->lock); } /* TLan_HandleInterrupts */ @@ -940,8 +832,7 @@ { TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); @@ -949,7 +840,7 @@ del_timer( &priv->timer ); free_irq( dev->irq, dev ); TLan_FreeLists( dev ); - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s closed.\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name ); MOD_DEC_USE_COUNT; @@ -983,8 +874,8 @@ /* Should only read stats if open ? */ TLan_ReadAndClearStats( dev, TLAN_RECORD ); - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount ); - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); if ( debug & TLAN_DEBUG_GNRL ) { TLan_PrintDio( dev->base_addr ); TLan_PhyPrint( dev ); @@ -1137,7 +1028,7 @@ TLanList *head_list; u32 ack = 1; - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); host_int = 0; head_list = priv->txList + priv->txHead; @@ -1155,10 +1046,10 @@ priv->stats.tx_bytes += head_list->frameSize; head_list->cStat = TLAN_CSTAT_UNUSED; - dev->tbusy = 0; + netif_start_queue(dev); CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); @@ -1254,7 +1145,7 @@ TLanList *tail_list; void *t; - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); host_int = 0; head_list = priv->rxList + priv->rxHead; tail_list = priv->rxList + priv->rxTail; @@ -1322,7 +1213,7 @@ CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); if ( eoc ) { - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; @@ -1408,7 +1299,7 @@ host_int = 0; if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); @@ -1464,16 +1355,16 @@ TLan_FreeLists( dev ); TLan_ResetLists( dev ); TLan_ResetAdapter( dev ); - dev->tbusy = 0; + netif_start_queue(dev); ack = 0; } else { - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Status Check\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name ); phy = priv->phy[priv->phyNum]; net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); if ( net_sts ) { TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Net_Sts = %x\n", dev->name, (unsigned) net_sts ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", dev->name, (unsigned) net_sts ); } if ( ( net_sts & TLAN_NET_STS_MIRQ ) && ( priv->phyNum == 0 ) ) { TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts ); @@ -1527,7 +1418,7 @@ host_int = 0; if ( priv->tlanRev < 0x30 ) { - TLAN_DBG( TLAN_DEBUG_RX, "TLAN RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); + TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO | TLAN_HC_RT; @@ -2017,7 +1908,7 @@ udelay( 1000 ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); if ( status & MII_GS_LINK ) { - printk( "TLAN: %s: Link active.\n", dev->name ); + printk( "TLAN: %s: Link active.\n", dev->name ); TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); } } @@ -2042,7 +1933,7 @@ outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); } else { printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name ); - TLan_SetTimer( dev, 1000, TLAN_TIMER_FINISH_RESET ); + TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET ); return; } @@ -2190,7 +2081,7 @@ TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo ); if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) { - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo ); + TLAN_DBG( TLAN_DEBUG_GNRL, "PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo ); if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) { priv->phy[1] = phy; } @@ -2215,7 +2106,7 @@ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; u16 value; - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Powering down PHY(s).\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name ); value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE; TLan_MiiSync( dev->base_addr ); TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); @@ -2228,7 +2119,7 @@ * This is abitrary. It is intended to make sure the * tranceiver settles. */ - TLan_SetTimer( dev, (50/(1000/HZ)), TLAN_TIMER_PHY_PUP ); + TLan_SetTimer( dev, (HZ/20), TLAN_TIMER_PHY_PUP ); } /* TLan_PhyPowerDown */ @@ -2240,7 +2131,7 @@ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; u16 value; - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Powering up PHY.\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name ); TLan_MiiSync( dev->base_addr ); value = MII_GC_LOOPBK; TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value ); @@ -2264,7 +2155,7 @@ phy = priv->phy[priv->phyNum]; - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Reseting PHY.\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Reseting PHY.\n", dev->name ); TLan_MiiSync( dev->base_addr ); value = MII_GC_LOOPBK | MII_GC_RESET; TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, value ); @@ -2296,7 +2187,7 @@ phy = priv->phy[priv->phyNum]; - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: %s: Trying to activate link.\n", dev->name ); + TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Trying to activate link.\n", dev->name ); TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status ); if ( ( status & MII_GS_AUTONEG ) && ( priv->duplex == TLAN_DUPLEX_DEFAULT ) && @@ -2325,7 +2216,7 @@ * but the card need additional time to start AN. * .5 sec should be plenty extra. */ - printk( "TLAN: %s: Starting autonegotiation.\n", dev->name ); + printk( "TLAN: %s: Starting autonegotiation.\n", dev->name ); TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; } @@ -2334,7 +2225,7 @@ priv->phyNum = 0; data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); - TLan_SetTimer( dev, 4, TLAN_TIMER_PHY_PDOWN ); + TLan_SetTimer( dev, (4*(HZ/1000)), TLAN_TIMER_PHY_PDOWN ); return; } else if ( priv->phyNum == 0 ) { TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl ); @@ -2382,12 +2273,12 @@ /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while. */ - printk( "TLAN: Giving autonegotiation more time.\n" ); + printk( "TLAN: Giving autonegotiation more time.\n" ); TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; } - printk( "TLAN: %s: Autonegotiation complete.\n", dev->name ); + printk( "TLAN: %s: Autonegotiation complete.\n", dev->name ); TLan_MiiReadReg( dev, phy, MII_AN_ADV, &an_adv ); TLan_MiiReadReg( dev, phy, MII_AN_LPA, &an_lpa ); mode = an_adv & an_lpa & 0x03E0; @@ -2401,7 +2292,7 @@ priv->phyNum = 0; data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data ); - TLan_SetTimer( dev, 40, TLAN_TIMER_PHY_PDOWN ); + TLan_SetTimer( dev, (400*(HZ/1000)), TLAN_TIMER_PHY_PDOWN ); return; } @@ -2474,9 +2365,7 @@ outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; - if ( dev->interrupt == 0 ) - spin_lock_irqsave(&priv->lock, flags); - dev->interrupt++; + spin_lock_irqsave(&priv->lock, flags); TLan_MiiSync(dev->base_addr); @@ -2523,10 +2412,7 @@ *val = tmp; - dev->interrupt--; - if ( dev->interrupt == 0 ) - spin_unlock_irqrestore(&priv->lock, flags); - + spin_unlock_irqrestore(&priv->lock, flags); return err; } /* TLan_MiiReadReg */ @@ -2643,9 +2529,7 @@ outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; - if ( dev->interrupt == 0 ) - spin_lock_irqsave(&priv->lock, flags); - dev->interrupt++; + spin_lock_irqsave(&priv->lock, flags); TLan_MiiSync( dev->base_addr ); @@ -2667,10 +2551,7 @@ if ( minten ) TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); - dev->interrupt--; - if ( dev->interrupt == 0 ) - spin_unlock_irqrestore(&priv->lock, flags); - + spin_unlock_irqrestore(&priv->lock, flags); } /* TLan_MiiWriteReg */ @@ -2871,9 +2752,7 @@ unsigned long flags = 0; int ret=0; - if ( dev->interrupt == 0 ) - spin_lock_irqsave(&priv->lock, flags); - dev->interrupt++; + spin_lock_irqsave(&priv->lock, flags); TLan_EeSendStart( dev->base_addr ); err = TLan_EeSendByte( dev->base_addr, 0xA0, TLAN_EEPROM_ACK ); @@ -2896,15 +2775,12 @@ goto fail; } TLan_EeReceiveByte( dev->base_addr, data, TLAN_EEPROM_STOP ); -fail: - dev->interrupt--; - if ( dev->interrupt == 0 ) - spin_unlock_irqrestore(&priv->lock, flags); +fail: + spin_unlock_irqrestore(&priv->lock, flags); return ret; } /* TLan_EeReadByte */ - diff -u --recursive --new-file v2.3.42/linux/drivers/net/tlan.h linux/drivers/net/tlan.h --- v2.3.42/linux/drivers/net/tlan.h Tue Jan 11 22:31:40 2000 +++ linux/drivers/net/tlan.h Mon Feb 7 09:53:21 2000 @@ -45,7 +45,7 @@ #define TLAN_IGNORE 0 #define TLAN_RECORD 1 -#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk( format, ##args ); +#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args ); #define TLAN_DEBUG_GNRL 0x0001 #define TLAN_DEBUG_TX 0x0002 #define TLAN_DEBUG_RX 0x0004 @@ -182,7 +182,6 @@ u32 duplex; u32 phy[2]; u32 phyNum; - u32 sa_int; u32 speed; u8 tlanRev; u8 tlanFullDuplex; diff -u --recursive --new-file v2.3.42/linux/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c --- v2.3.42/linux/drivers/net/tokenring/smctr.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/net/tokenring/smctr.c Thu Feb 10 12:32:43 2000 @@ -3684,13 +3684,7 @@ int ioaddr = smctr_portlist[i]; if(check_region(ioaddr, SMCTR_IO_EXTENT)) continue; - if(smctr_probe1(dev, ioaddr)) - { -#ifndef MODULE - tr_freedev(dev); -#endif - } - else + if (!smctr_probe1(dev, ioaddr)) return (0); } diff -u --recursive --new-file v2.3.42/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.3.42/linux/drivers/net/tulip.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/tulip.c Thu Feb 10 12:28:01 2000 @@ -75,6 +75,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include @@ -101,10 +102,6 @@ #define IRQ(irq, dev_id, pt_regs) (irq, pt_regs) #endif -#if (LINUX_VERSION_CODE < 0x20123) -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif - /* This my implementation of shared IRQs, now only used for 1.2.13. */ #ifdef HAVE_SHARED_IRQ #define USE_SHARED_IRQ @@ -368,16 +365,9 @@ u32 setup_frame[48]; /* Pseudo-Tx frame to init address table. */ int chip_id; int revision; -#if LINUX_VERSION_CODE > 0x20139 struct net_device_stats stats; -#else - struct enet_statistics stats; -#endif struct timer_list timer; /* Media selection timer. */ - int interrupt; /* In-interrupt flag. */ -#ifdef SMP_CHECK - int smp_proc_id; /* Which processor in IRQ handler. */ -#endif + spinlock_t tx_lock; unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ unsigned int tx_full:1; /* The Tx queue is full. */ @@ -435,7 +425,7 @@ This allows the probe routine to use the old driver initialization interface. */ -int tulip_probe(void) +static int __init tulip_probe(void) { int cards_found = 0; static int pci_index = 0; /* Static, for multiple probe calls. */ @@ -446,17 +436,13 @@ well with the current structure. So instead we detect just the Tulip cards in slot order. */ -#if LINUX_VERSION_CODE >= 0x20155 if (! pci_present()) return -ENODEV; -#else - if (! pcibios_present()) - return -ENODEV; -#endif for (;pci_index < 0xff; pci_index++) { u16 vendor, device, pci_command, new_command; unsigned long pci_ioaddr = 0; int chip_idx = 0; + struct pci_dev *pdev; if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, @@ -468,10 +454,10 @@ else break; } - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); + + pdev = pci_find_slot (pci_bus, pci_device_fn); + vendor = pdev->vendor; + device = pdev->device; for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++) if (vendor == tulip_tbl[chip_idx].vendor_id && @@ -485,12 +471,7 @@ vendor, device); continue; } -#if LINUX_VERSION_CODE >= 0x20155 pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->resource[0].start; -#else - pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, - &pci_ioaddr); -#endif /* Remove I/O space marker in bit 0. */ pci_ioaddr &= ~3; @@ -501,37 +482,32 @@ if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size)) continue; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; if (pci_command != new_command) { printk(KERN_INFO " The PCI BIOS has not enabled this" " device! Updating PCI command %4.4x->%4.4x.\n", pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); + pci_write_config_word(pdev, PCI_COMMAND, new_command); } if(tulip_probe1(pci_bus, pci_device_fn, chip_idx, cards_found)) { /* Get and check the bus-master and latency values. */ unsigned char pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 10) { printk(KERN_INFO " PCI latency timer (CFLT) is " "unreasonably low at %d. Setting to 64 clocks.\n", pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 64); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); } else if (tulip_debug > 1) printk(KERN_INFO " PCI latency timer (CFLT) is %#x, " " PCI command is %4.4x.\n", pci_latency, new_command); /* Bring the 21143 out power-down mode. */ if (device == PCI_DEVICE_ID_DEC_TULIP_21142) - pcibios_write_config_dword(pci_bus, pci_device_fn, - 0x40, 0x40000000); + pci_write_config_dword(pdev, 0x40, 0x40000000); cards_found++; } } @@ -753,6 +729,8 @@ /* The Tulip-specific entries in the device structure. */ dev->open = &tulip_open; dev->hard_start_xmit = &tulip_start_xmit; + dev->tx_timeout = &tulip_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; dev->stop = &tulip_close; dev->get_stats = &tulip_get_stats; #ifdef HAVE_PRIVATE_IOCTL @@ -1216,9 +1194,7 @@ /* When a module we don't have 'x86' to check. */ outl(0x01A00000 | 0x4800, ioaddr + CSR0); #else -#if (LINUX_VERSION_CODE > 0x2014c) #define x86 boot_cpu_data.x86 -#endif outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0); if (x86 <= 4) printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache " @@ -1249,6 +1225,7 @@ MOD_INC_USE_COUNT; + spin_lock_init(&tp->tx_lock); tulip_init_ring(dev); /* This is set_rx_mode(), but without starting the transmitter. */ @@ -1329,10 +1306,6 @@ outl(tp->csr6, ioaddr + CSR6); outl(tp->csr6 | 0x2000, ioaddr + CSR6); - dev->tbusy = 0; - tp->interrupt = 0; - dev->start = 1; - /* Enable interrupts by setting the interrupt mask. */ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); @@ -1352,6 +1325,8 @@ tp->timer.function = tulip_tbl[tp->chip_id].media_timer; add_timer(&tp->timer); + netif_start_queue(dev); + return 0; } @@ -1958,9 +1933,13 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; + printk("%s: transmit timed out\n", dev->name); + if (media_cap[dev->if_port] & MediaIsMII) { /* Do nothing -- the media monitor should handle this. */ +#if 0 if (tulip_debug > 1) +#endif printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", dev->name); dev->trans_start = jiffies; @@ -2090,19 +2069,13 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; int entry; u32 flag; - - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - tulip_tx_timeout(dev); - return 1; - } + unsigned long cpuflags; /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ + spin_lock_irqsave(&tp->tx_lock, cpuflags); + /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % TX_RING_SIZE; @@ -2111,17 +2084,15 @@ if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ flag = 0x60000000; /* No interrupt */ - dev->tbusy = 0; } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { flag = 0xe0000000; /* Tx-done intr. */ - dev->tbusy = 0; } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { flag = 0x60000000; /* No Tx-done intr. */ - dev->tbusy = 0; } else { /* Leave room for set_rx_mode() to fill entries. */ flag = 0xe0000000; /* Tx-done intr. */ tp->tx_full = 1; + netif_stop_queue(dev); } if (entry == TX_RING_SIZE-1) flag |= 0xe2000000; @@ -2129,6 +2100,8 @@ tp->tx_ring[entry].length = skb->len | flag; tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */ tp->cur_tx++; + spin_unlock_irqrestore(&tp->tx_lock, cpuflags); + /* Trigger an immediate transmit demand. */ outl(0, dev->base_addr + CSR1); @@ -2159,20 +2132,6 @@ ioaddr = dev->base_addr; tp = (struct tulip_private *)dev->priv; - if (test_and_set_bit(0, (void*)&tp->interrupt)) { -#ifdef SMP_CHECK - printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d," - " proc %d already handling.\n", dev->name, - tp->smp_proc_id, smp_processor_id()); -#else - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); -#endif - return; - } - dev->interrupt = 1; -#ifdef SMP_CHECK - tp->smp_proc_id = smp_processor_id(); -#endif do { csr5 = inl(ioaddr + CSR5); @@ -2189,6 +2148,8 @@ if (csr5 & (RxIntr | RxNoBuf)) work_budget -= tulip_rx(dev); + spin_lock(&tp->tx_lock); + if (csr5 & (TxNoBuf | TxDied | TxIntr)) { unsigned int dirty_tx; @@ -2224,19 +2185,13 @@ #ifdef ETHER_STATS if (status & 0x0001) tp->stats.tx_deferred++; #endif -#if LINUX_VERSION_CODE > 0x20127 tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff; -#endif tp->stats.collisions += (status >> 3) & 15; tp->stats.tx_packets++; } /* Free the original skb. */ -#if (LINUX_VERSION_CODE > 0x20155) - dev_kfree_skb(tp->tx_skbuff[entry]); -#else - dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE); -#endif + dev_kfree_skb_irq(tp->tx_skbuff[entry]); tp->tx_skbuff[entry] = 0; } @@ -2248,15 +2203,14 @@ } #endif - if (tp->tx_full && dev->tbusy - && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { + if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { /* The ring is no longer full, clear tbusy. */ tp->tx_full = 0; - dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(dev); } tp->dirty_tx = dirty_tx; + if (csr5 & TxDied) { if (tulip_debug > 1) printk(KERN_WARNING "%s: The transmitter stopped!" @@ -2266,6 +2220,7 @@ outl(tp->csr6 | 0x2002, ioaddr + CSR6); } } + spin_unlock(&tp->tx_lock); /* Log errors. */ if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ @@ -2316,8 +2271,6 @@ printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", dev->name, inl(ioaddr + CSR5)); - dev->interrupt = 0; - clear_bit(0, (void*)&tp->interrupt); return; } @@ -2397,9 +2350,7 @@ netif_rx(skb); dev->last_rx = jiffies; tp->stats.rx_packets++; -#if LINUX_VERSION_CODE > 0x20127 tp->stats.rx_bytes += pkt_len; -#endif } entry = (++tp->cur_rx) % RX_RING_SIZE; } @@ -2429,8 +2380,7 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (tulip_debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", @@ -2463,23 +2413,12 @@ tp->rx_ring[i].length = 0; tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ if (skb) { -#if LINUX_VERSION_CODE < 0x20100 - skb->free = 1; -#endif -#if (LINUX_VERSION_CODE > 0x20155) dev_kfree_skb(skb); -#else - dev_kfree_skb(skb, FREE_WRITE); -#endif } } for (i = 0; i < TX_RING_SIZE; i++) { if (tp->tx_skbuff[i]) -#if (LINUX_VERSION_CODE > 0x20155) dev_kfree_skb(tp->tx_skbuff[i]); -#else - dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE); -#endif tp->tx_skbuff[i] = 0; } @@ -2495,7 +2434,7 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; - if (dev->start) + if (test_bit(LINK_STATE_START, &dev->state)) tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; return &tp->stats; @@ -2601,6 +2540,7 @@ long ioaddr = dev->base_addr; int csr6 = inl(ioaddr + CSR6) & ~0x00D5; struct tulip_private *tp = (struct tulip_private *)dev->priv; + unsigned long cpuflags; tp->csr6 &= ~0x00D5; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ @@ -2660,13 +2600,12 @@ *setup_frm++ = eaddrs[2]; } while (++i < 15); /* Now add this frame to the Tx list. */ + spin_lock_irqsave(&tp->tx_lock, cpuflags); if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { /* Same setup recently queued, we need not add it. */ } else { - unsigned long flags; unsigned int entry, dummy = 0; - save_flags(flags); cli(); entry = tp->cur_tx++ % TX_RING_SIZE; if (entry != 0) { @@ -2688,12 +2627,12 @@ tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); tp->tx_ring[entry].status = 0x80000000; if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { - dev->tbusy = 1; + netif_stop_queue(dev); tp->tx_full = 1; } if (dummy >= 0) tp->tx_ring[dummy].status = DescOwned; - restore_flags(flags); + spin_unlock_irqrestore(&tp->tx_lock, cpuflags); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); } @@ -2711,12 +2650,14 @@ u32 io; u8 bus, devfn; struct net_device *dev; + struct pci_dev *pdev; if (loc->bus != LOC_PCI) return NULL; - bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; + pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); + if (!pdev) return NULL; printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn); - pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io); - pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id); + io = pdev->resource[0].start; + dev_id = pdev->device; io &= ~3; dev = tulip_probe1(bus, devfn, DC21142, -1); if (dev) { @@ -2753,9 +2694,6 @@ #endif /* Cardbus support */ - -#ifdef MODULE -#if LINUX_VERSION_CODE > 0x20118 MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); MODULE_PARM(debug, "i"); @@ -2764,13 +2702,11 @@ MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -#endif /* An additional parameter that may be passed in... */ static int debug = -1; -int -init_module(void) +static int __init tulip_init_module (void) { if (debug >= 0) tulip_debug = debug; @@ -2783,8 +2719,7 @@ #endif } -void -cleanup_module(void) +static void __exit tulip_cleanup_module (void) { struct net_device *next_dev; @@ -2802,8 +2737,10 @@ } } -#endif /* MODULE */ - +module_init(tulip_init_module); +module_exit(tulip_cleanup_module); + + /* * Local variables: * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" diff -u --recursive --new-file v2.3.42/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.3.42/linux/drivers/net/via-rhine.c Thu Nov 11 20:11:42 1999 +++ linux/drivers/net/via-rhine.c Thu Feb 10 12:28:01 2000 @@ -66,7 +66,6 @@ #include #include -#include #include #include #include @@ -77,6 +76,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -109,10 +109,6 @@ #define RUN_AT(x) (jiffies + (x)) -#ifdef MODULE -char kernel_version[] = UTS_RELEASE; -#endif -#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); @@ -121,27 +117,6 @@ MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -#endif -#if LINUX_VERSION_CODE < 0x20123 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#else -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -/* Grrrr, the PCI code changed, but did not consider CardBus... */ -#include -#define PCI_SUPPORT_VER1 -#else -#define PCI_SUPPORT_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE); -#else -#define dev_free_skb(skb) dev_kfree_skb(skb); -#endif /* @@ -248,10 +223,10 @@ const char *name; u16 vendor_id, device_id, device_id_mask, flags; int io_size; - struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); + struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt); }; -static struct net_device *via_probe1(int pci_bus, int pci_devfn, long ioaddr, int irq, +static struct net_device *via_probe1(struct pci_dev *pdev, long ioaddr, int irq, int chp_idx, int fnd_cnt); static struct pci_id_info pci_tbl[] = { @@ -343,7 +318,7 @@ struct net_device *next_module; /* Link for devices of this type. */ struct net_device_stats stats; struct timer_list timer; /* Media monitoring timer. */ - unsigned char pci_bus, pci_devfn; + spinlock_t lock; /* Frequently used values: keep some adjacent for cache effect. */ int chip_id; long in_interrupt; /* Word-long for SMP locks. */ @@ -398,23 +373,22 @@ unsigned char pci_bus, pci_device_fn; struct net_device *dev; - if ( ! pcibios_present()) - return -ENODEV; - for (;pci_index < 0xff; pci_index++) { u16 vendor, device, pci_command, new_command; int chip_idx, irq; long pciaddr; long ioaddr; + struct pci_dev *pdev; if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); + + pdev = pci_find_slot (pci_bus, pci_device_fn); + if (!pdev) continue; + vendor = pdev->vendor; + device = pdev->device; for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) if (vendor == pci_tbl[chip_idx].vendor_id @@ -424,32 +398,12 @@ if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ continue; - { -#if defined(PCI_SUPPORT_VER2) - struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); #ifdef VIA_USE_IO - pciaddr = pdev->resource[0].start; + pciaddr = pdev->resource[0].start; #else - pciaddr = pdev->resource[1].start; + pciaddr = pdev->resource[1].start; #endif - irq = pdev->irq; -#else - u32 pci_memaddr; - u8 pci_irq_line; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); -#ifdef VIA_USE_IO - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_memaddr); - pciaddr = pci_memaddr; -#else - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, &pci_memaddr); - pciaddr = pci_memaddr; -#endif - irq = pci_irq_line; -#endif - } + irq = pdev->irq; if (debug > 2) printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", @@ -466,30 +420,25 @@ continue; } - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); new_command = pci_command | (pci_tbl[chip_idx].flags & 7); if (pci_command != new_command) { printk(KERN_INFO " The PCI BIOS has not enabled the" " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); + pdev->bus->number, pdev->devfn, pci_command, new_command); + pci_write_config_word(pdev, PCI_COMMAND, new_command); } - dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, ioaddr, - irq, chip_idx, cards_found); + dev = pci_tbl[chip_idx].probe1(pdev, ioaddr, irq, chip_idx, cards_found); if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { u8 pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < min_pci_latency) { printk(KERN_INFO " PCI latency timer (CFLT) is " "unreasonably low at %d. Setting to %d clocks.\n", pci_latency, min_pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, min_pci_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency); } } dev = 0; @@ -499,17 +448,10 @@ return cards_found ? 0 : -ENODEV; } -#ifndef MODULE -int via_rhine_probe(void) -{ - printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); - return pci_etherdev_probe(pci_tbl); -} -#endif -static struct net_device *via_probe1(int pci_bus, int pci_devfn, - long ioaddr, int irq, - int chip_id, int card_idx) +static struct net_device *via_probe1(struct pci_dev *pdev, + long ioaddr, int irq, + int chip_id, int card_idx) { struct net_device *dev; struct netdev_private *np; @@ -522,6 +464,14 @@ printk(KERN_INFO "%s: %s at 0x%lx, ", dev->name, pci_tbl[chip_id].name, ioaddr); +#ifdef VIA_USE_IO + if (!request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name)) { + unregister_netdev (dev); + kfree (dev); + return NULL; + } +#endif + /* Ideally we would be read the EEPROM but access may be locked. */ for (i = 0; i <6; i++) dev->dev_addr[i] = readb(ioaddr + StationAddr + i); @@ -529,10 +479,6 @@ printk("%2.2x:", dev->dev_addr[i]); printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); -#ifdef VIA_USE_IO - request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name); -#endif - /* Reset the chip to erase previous misconfiguration. */ writew(CmdReset, ioaddr + ChipCmd); @@ -548,8 +494,7 @@ np->next_module = root_net_dev; root_net_dev = dev; - np->pci_bus = pci_bus; - np->pci_devfn = pci_devfn; + np->lock = SPIN_LOCK_UNLOCKED; np->chip_id = chip_id; if (dev->mem_start) @@ -576,6 +521,8 @@ dev->get_stats = &get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; if (cap_tbl[np->chip_id].flags & CanHaveMII) { int phy, phy_idx = 0; @@ -671,14 +618,11 @@ if (dev->if_port == 0) dev->if_port = np->default_port; - dev->tbusy = 0; - dev->interrupt = 0; + netif_start_queue(dev); np->in_interrupt = 0; set_rx_mode(dev); - dev->start = 1; - /* Enable interrupts by setting the interrupt mask. */ writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| IntrTxDone | IntrTxAbort | IntrTxUnderrun | @@ -824,15 +768,6 @@ struct netdev_private *np = (struct netdev_private *)dev->priv; unsigned entry; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - tx_timeout(dev); - return 1; - } - /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -862,7 +797,7 @@ writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1) - clear_bit(0, (void*)&dev->tbusy); /* Typical path */ + netif_start_queue(dev); /* Typical path */ else np->tx_full = 1; dev->trans_start = jiffies; @@ -884,21 +819,8 @@ ioaddr = dev->base_addr; np = (struct netdev_private *)dev->priv; -#if defined(__i386__) - /* A lock to prevent simultaneous entry bug on Intel SMP machines. */ - if (test_and_set_bit(0, (void*)&dev->interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - dev->interrupt = 0; /* Avoid halting machine. */ - return; - } -#else - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } - dev->interrupt = 1; -#endif + + spin_lock (&np->lock); do { u32 intr_status = readw(ioaddr + IntrStatus); @@ -936,30 +858,22 @@ if (txstatus & 0x0100) np->stats.tx_aborted_errors++; if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++; if (txstatus & 0x0002) np->stats.tx_fifo_errors++; -#ifdef ETHER_STATS - if (txstatus & 0x0100) np->stats.collisions16++; -#endif /* Transmitter restarted in 'abnormal' handler. */ } else { -#ifdef ETHER_STATS - if (txstatus & 0x0001) np->stats.tx_deferred++; -#endif np->stats.collisions += (txstatus >> 3) & 15; -#if defined(NETSTATS_VER2) np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff; -#endif np->stats.tx_packets++; } /* Free the original skb. */ - dev_free_skb(np->tx_skbuff[entry]); + kfree_skb(np->tx_skbuff[entry]); np->tx_skbuff[entry] = 0; } - if (np->tx_full && dev->tbusy - && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { + if (np->tx_full && + test_bit(LINK_STATE_XOFF, &dev->flags) && + np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { /* The ring is no longer full, clear tbusy. */ np->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (dev); } /* Abnormal error summary/uncommon events handlers. */ @@ -979,12 +893,7 @@ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, readw(ioaddr + IntrStatus)); -#if defined(__i386__) - clear_bit(0, (void*)&dev->interrupt); -#else - dev->interrupt = 0; -#endif - return; + spin_unlock (&np->lock); } /* This routine is logically part of the interrupt handler, but isolated @@ -1217,8 +1126,7 @@ struct netdev_private *np = (struct netdev_private *)dev->priv; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (debug > 1) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", @@ -1239,16 +1147,13 @@ np->rx_ring[i].rx_length = 0; np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (np->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - np->rx_skbuff[i]->free = 1; -#endif - dev_free_skb(np->rx_skbuff[i]); + kfree_skb(np->rx_skbuff[i]); } np->rx_skbuff[i] = 0; } for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) - dev_free_skb(np->tx_skbuff[i]); + kfree_skb(np->tx_skbuff[i]); np->tx_skbuff[i] = 0; } @@ -1257,9 +1162,7 @@ return 0; } - -#ifdef MODULE -int init_module(void) +static int __init via_rhine_init_module (void) { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); @@ -1271,7 +1174,7 @@ #endif } -void cleanup_module(void) +static void __exit via_rhine_cleanup_module (void) { #ifdef CARDBUS @@ -1296,8 +1199,10 @@ } } -#endif /* MODULE */ - +module_init(via_rhine_init_module); +module_exit(via_rhine_cleanup_module); + + /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" diff -u --recursive --new-file v2.3.42/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c --- v2.3.42/linux/drivers/net/wan/cosa.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/net/wan/cosa.c Wed Feb 9 11:42:35 2000 @@ -313,23 +313,16 @@ #endif static struct file_operations cosa_fops = { - cosa_lseek, - cosa_read, - cosa_write, - NULL, /* readdir */ - cosa_poll, - cosa_chardev_ioctl, - NULL, /* mmap */ - cosa_open, - NULL, /* flush */ - cosa_release, - NULL, /* fsync */ + llseek: cosa_lseek, + read: cosa_read, + write: cosa_write, + poll: cosa_poll, + ioctl: cosa_chardev_ioctl, + open: cosa_open, + release: cosa_release, #ifdef COSA_FASYNC_WORKING - cosa_fasync, -#else - NULL, + fasync: cosa_fasync, #endif - NULL /* lock */ }; /* Ioctls */ diff -u --recursive --new-file v2.3.42/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.3.42/linux/drivers/net/yellowfin.c Thu Nov 11 20:11:42 1999 +++ linux/drivers/net/yellowfin.c Thu Feb 10 12:28:01 2000 @@ -74,6 +74,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -83,27 +84,9 @@ #include #include -/* Kernel compatibility defines, most common to the PCCard package. */ -#include /* Evil and unneccessary */ - #define RUN_AT(x) (jiffies + (x)) -#if (LINUX_VERSION_CODE < 0x20123) -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20155 -#define PCI_SUPPORT_VER1 -#define pci_present pcibios_present -#endif -#if LINUX_VERSION_CODE < 0x20159 -#define DEV_FREE_SKB(skb) dev_kfree_skb(skb, FREE_WRITE); -#else #define DEV_FREE_SKB(skb) dev_kfree_skb(skb); -#endif /* The PCI I/O space extent. */ #define YELLOWFIN_TOTAL_SIZE 0x100 @@ -280,9 +263,9 @@ struct tx_status_words tx_status[TX_RING_SIZE]; struct timer_list timer; /* Media selection timer. */ struct enet_statistics stats; + spinlock_t lock; /* Frequently used and paired value: keep adjacent for cache effect. */ int chip_id; - int in_interrupt; struct yellowfin_desc *rx_head_desc; struct tx_status_words *tx_tail_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ @@ -300,9 +283,6 @@ u32 pad[4]; /* Used for 32-byte alignment */ }; -#ifdef MODULE - -#if LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); @@ -312,9 +292,6 @@ MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -#endif - -#endif static struct net_device *yellowfin_probe1(long ioaddr, int irq, int chip_id, int options); static int read_eeprom(long ioaddr, int location); @@ -340,7 +317,7 @@ /* A list of all installed Yellowfin devices, for removing the driver module. */ static struct net_device *root_yellowfin_dev = NULL; -int yellowfin_probe(void) +static int __init yellowfin_probe(void) { int cards_found = 0; int pci_index = 0; @@ -355,6 +332,7 @@ int chip_idx; int irq; long ioaddr; + struct pci_dev *pdev; if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, @@ -362,10 +340,10 @@ != PCIBIOS_SUCCESSFUL) break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); + pdev = pci_find_slot (pci_bus, pci_device_fn); + if (!pdev) break; + vendor = pdev->vendor; + device = pdev->device; for (chip_idx = 0; chip_tbl[chip_idx].vendor_id; chip_idx++) if (vendor == chip_tbl[chip_idx].vendor_id @@ -388,28 +366,24 @@ if (check_region(ioaddr, YELLOWFIN_TOTAL_SIZE)) continue; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; if (pci_command != new_command) { printk(KERN_INFO " The PCI BIOS has not enabled the" " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); + pci_write_config_word(pdev, PCI_COMMAND, new_command); } if(yellowfin_probe1(ioaddr, irq, chip_idx, cards_found)) { /* Get and check the bus-master and latency values. */ - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < min_pci_latency) { printk(KERN_INFO " PCI latency timer (CFLT) is " "unreasonably low at %d. Setting to %d clocks.\n", pci_latency, min_pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, min_pci_latency); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, min_pci_latency); } else if (yellowfin_debug > 1) printk(KERN_INFO " PCI latency timer (CFLT) is %#x.\n", pci_latency); @@ -465,6 +439,7 @@ root_yellowfin_dev = dev; yp->chip_id = chip_id; + yp->lock = SPIN_LOCK_UNLOCKED; option = card_idx < MAX_UNITS ? options[card_idx] : 0; if (dev->mem_start) @@ -493,6 +468,9 @@ #ifdef HAVE_PRIVATE_IOCTL dev->do_ioctl = &mii_ioctl; #endif + dev->tx_timeout = yellowfin_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + if (mtu) dev->mtu = mtu; @@ -602,9 +580,7 @@ if (dev->if_port == 0) dev->if_port = yp->default_port; - dev->tbusy = 0; - dev->interrupt = 0; - yp->in_interrupt = 0; + netif_start_queue(dev); /* Setting the Rx mode will start the Rx process. */ if (yp->chip_id == 0) { @@ -618,8 +594,6 @@ } set_rx_mode(dev); - dev->start = 1; - /* Enable interrupts by setting the interrupt mask. */ outw(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */ outw(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ @@ -787,15 +761,6 @@ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; unsigned entry; - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - if (jiffies - dev->trans_start < TX_TIMEOUT) - return 1; - yellowfin_tx_timeout(dev); - return 1; - } - /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -840,7 +805,7 @@ outl(0x10001000, dev->base_addr + TxCtrl); if (yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 1) - clear_bit(0, (void*)&dev->tbusy); /* Typical path */ + netif_start_queue(dev); /* Typical path */ else yp->tx_full = 1; dev->trans_start = jiffies; @@ -869,11 +834,8 @@ ioaddr = dev->base_addr; yp = (struct yellowfin_private *)dev->priv; - if (test_and_set_bit(0, (void*)&yp->in_interrupt)) { - dev->interrupt = 1; - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } + + spin_lock (&yp->lock); do { u16 intr_status = inw(ioaddr + IntrClear); @@ -900,12 +862,12 @@ yp->tx_skbuff[entry] = 0; yp->stats.tx_packets++; } - if (yp->tx_full && dev->tbusy - && yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 4) { + if (yp->tx_full && + test_bit(LINK_STATE_XOFF, &dev->flags) && + yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 4) { /* The ring is no longer full, clear tbusy. */ yp->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (dev); } #else if (intr_status & IntrTxDone @@ -973,12 +935,12 @@ } #endif - if (yp->tx_full && dev->tbusy - && yp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { + if (yp->tx_full && + test_bit(LINK_STATE_XOFF, &dev->flags) && + yp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { /* The ring is no longer full, clear tbusy. */ yp->tx_full = 0; - clear_bit(0, (void*)&dev->tbusy); - mark_bh(NET_BH); + netif_wake_queue (dev); } yp->dirty_tx = dirty_tx; @@ -1004,15 +966,14 @@ /* Code that should never be run! Perhaps remove after testing.. */ { static int stopit = 10; - if (dev->start == 0 && --stopit < 0) { + if ((!test_bit(LINK_STATE_START, &dev->state)) && --stopit < 0) { printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", dev->name); free_irq(irq, dev); } } - dev->interrupt = 0; - clear_bit(0, (void*)&yp->in_interrupt); + spin_lock (&yp->lock); return; } @@ -1171,8 +1132,7 @@ struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; int i; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); if (yellowfin_debug > 1) { printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", @@ -1233,9 +1193,6 @@ yp->rx_ring[i].cmd = CMD_STOP; yp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (yp->rx_skbuff[i]) { -#if LINUX_VERSION_CODE < 0x20100 - yp->rx_skbuff[i]->free = 1; -#endif DEV_FREE_SKB(yp->rx_skbuff[i]); } yp->rx_skbuff[i] = 0; @@ -1358,13 +1315,11 @@ } #endif /* HAVE_PRIVATE_IOCTL */ - -#ifdef MODULE /* An additional parameter that may be passed in... */ static int debug = -1; -int init_module(void) +static int __init yellowfin_init_module(void) { if (debug >= 0) yellowfin_debug = debug; @@ -1372,7 +1327,7 @@ return yellowfin_probe(); } -void cleanup_module(void) +static void __exit yellowfin_cleanup_module (void) { struct net_device *next_dev; @@ -1386,8 +1341,10 @@ } } -#endif /* MODULE */ - +module_init(yellowfin_init_module); +module_exit(yellowfin_cleanup_module); + + /* * Local variables: * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" diff -u --recursive --new-file v2.3.42/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c --- v2.3.42/linux/drivers/parport/ieee1284_ops.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/parport/ieee1284_ops.c Wed Feb 9 19:51:24 2000 @@ -257,7 +257,7 @@ if (parport_read_status (port) & PARPORT_STATUS_ERROR) { port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; DPRINTK (KERN_DEBUG - "%s: No more byte data (%d bytes)\n", + "%s: No more byte data (%Zd bytes)\n", port->name, count); /* Go to reverse idle phase. */ @@ -735,23 +735,29 @@ PARPORT_CONTROL_SELECT); port->ops->data_forward (port); for (; len > 0; len--, bp++) { + /* Event 62: Write data and strobe data */ parport_write_data (port, *bp); - - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY)) - break; - - /* Strobe data */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + /* Event 58 */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10)) break; + /* Event 63 */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + + /* Event 60 */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) + break; + ret++; } + /* Event 61 */ + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + return ret; } @@ -766,23 +772,24 @@ parport_frob_control (port, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT, 0); port->ops->data_reverse (port); for (; len > 0; len--, bp++) { - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY)) + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); + + /* Event 58 */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 10)) break; + *bp = parport_read_data (port); + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) break; - *bp = parport_read_data (port); - - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); ret++; } port->ops->data_forward (port); @@ -807,23 +814,25 @@ PARPORT_CONTROL_SELECT); port->ops->data_forward (port); for (; len > 0; len--, bp++) { + /* Write data and assert nAStrb. */ parport_write_data (port, *bp); - - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY)) - break; - - /* Strobe data */ parport_frob_control (port, PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 10)) break; parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + break; + ret++; } + parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); + return ret; } @@ -838,23 +847,24 @@ parport_frob_control (port, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT | PARPORT_CONTROL_AUTOFD, 0); port->ops->data_reverse (port); for (; len > 0; len--, bp++) { - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY)) + parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); + + /* Event 58 */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 10)) break; + *bp = parport_read_data (port); + parport_frob_control (port, PARPORT_CONTROL_SELECT, PARPORT_CONTROL_SELECT); - if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) break; - *bp = parport_read_data (port); - - parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); ret++; } port->ops->data_forward (port); diff -u --recursive --new-file v2.3.42/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.3.42/linux/drivers/parport/parport_pc.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/parport/parport_pc.c Wed Feb 9 19:49:33 2000 @@ -551,21 +551,22 @@ unsigned long dmaflag; size_t left = length; const struct parport_pc_private *priv = port->physport->private_data; - unsigned long dma_addr; + dma_addr_t dma_addr, dma_handle; size_t maxlen = 0x10000; /* max 64k per DMA transfer */ unsigned long start = (unsigned long) buf; unsigned long end = (unsigned long) buf + length - 1; - /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */ - if (end <= MAX_DMA_ADDRESS) { - /* If it would cross a 64k boundary, cap it at the end. */ - if ((start ^ end) & ~0xffff) - maxlen = (0x10000 - start) & 0xffff; + if (end < MAX_DMA_ADDRESS) { + /* If it would cross a 64k boundary, cap it at the end. */ + if ((start ^ end) & ~0xffffUL) + maxlen = (0x10000 - start) & 0xffff; - dma_addr = virt_to_bus(buf); + dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length); } else { - dma_addr = priv->dma_handle; + /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */ maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ + dma_addr = priv->dma_handle; + dma_handle = 0; } port = port->physport; @@ -585,7 +586,7 @@ if (count > maxlen) count = maxlen; - if (maxlen == PAGE_SIZE) /* bounce buffer ! */ + if (!dma_handle) /* bounce buffer ! */ memcpy(priv->dma_buf, buf, count); dmaflag = claim_dma_lock(); @@ -607,6 +608,7 @@ /* assume DMA will be successful */ left -= count; buf += count; + if (dma_handle) dma_addr += count; /* Wait for interrupt. */ false_alarm: @@ -645,6 +647,7 @@ /* update for possible DMA residue ! */ buf -= count; left += count; + if (dma_handle) dma_addr -= count; } /* Maybe got here through break, so adjust for DMA residue! */ @@ -656,6 +659,9 @@ /* Turn off DMA mode */ frob_econtrol (port, 1<<3, 0); + + if (dma_handle) + pci_unmap_single(priv->dev, dma_handle, length); return length - left; } @@ -1661,6 +1667,7 @@ p->dma = PARPORT_DMA_NONE; } +#ifdef CONFIG_PARPORT_PC_FIFO if (p->dma != PARPORT_DMA_NONE) { if (request_dma (p->dma, p->name)) { printk (KERN_WARNING "%s: dma %d in use, " @@ -1682,6 +1689,7 @@ } } } +#endif /* CONFIG_PARPORT_PC_FIFO */ } /* Done probing. Now put the port into a sensible start-up state. diff -u --recursive --new-file v2.3.42/linux/drivers/parport/probe.c linux/drivers/parport/probe.c --- v2.3.42/linux/drivers/parport/probe.c Wed Jul 28 11:22:46 1999 +++ linux/drivers/parport/probe.c Wed Feb 9 19:51:24 2000 @@ -164,8 +164,9 @@ retval = parport_read (dev->port, buffer, len); if (retval != len) - printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n", - dev->port->name, retval, len); + printk (KERN_DEBUG "%s: only read %Zd of %Zd ID bytes\n", + dev->port->name, retval, + len); /* Some printer manufacturers mistakenly believe that the length field is supposed to be _exclusive_. */ @@ -179,7 +180,7 @@ if (diff) printk (KERN_DEBUG "%s: device reported incorrect " - "length field (%d, should be %d)\n", + "length field (%d, should be %Zd)\n", dev->port->name, idlen, retval); else { /* One semi-colon short of a device ID. */ diff -u --recursive --new-file v2.3.42/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.3.42/linux/drivers/pci/pci.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/pci/pci.c Thu Feb 10 12:24:54 2000 @@ -96,7 +96,17 @@ pci_read_config_word(dev, PCI_STATUS, &status); if (!(status & PCI_STATUS_CAP_LIST)) return 0; - pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos); + switch (dev->hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos); + break; + case PCI_HEADER_TYPE_CARDBUS: + pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos); + break; + default: + return 0; + } while (ttl-- && pos >= 0x40) { pos &= ~3; pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id); @@ -297,9 +307,11 @@ void pci_remove_device(struct pci_dev *dev) { - if (dev->driver->remove) - dev->driver->remove(dev); - dev->driver = NULL; + if (dev->driver) { + if (dev->driver->remove) + dev->driver->remove(dev); + dev->driver = NULL; + } list_del(&dev->bus_list); list_del(&dev->global_list); pci_free_resources(dev); @@ -389,7 +401,7 @@ * Translate the low bits of the PCI base * to the resource type */ -static inline unsigned int pci_resource_flags(unsigned int flags) +static inline unsigned int pci_calc_resource_flags(unsigned int flags) { if (flags & PCI_BASE_ADDRESS_SPACE_IO) return IORESOURCE_IO; @@ -433,7 +445,7 @@ sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff; } res->end = res->start + (unsigned long) sz; - res->flags |= (l & 0xf) | pci_resource_flags(l); + res->flags |= (l & 0xf) | pci_calc_resource_flags(l); if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { pci_read_config_dword(dev, reg+4, &l); diff -u --recursive --new-file v2.3.42/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.3.42/linux/drivers/pci/pci.ids Fri Jan 21 18:19:16 2000 +++ linux/drivers/pci/pci.ids Mon Feb 7 19:45:28 2000 @@ -4,7 +4,7 @@ # Maintained by Martin Mares # If you have any new entries, send them to the maintainer. # -# $Id: pci.ids,v 1.46 2000/01/02 20:32:11 mj Exp $ +# $Id: pci.ids,v 1.50 2000/01/23 05:57:06 mj Exp $ # # Vendors, devices and subsystems. Please keep sorted. @@ -356,12 +356,16 @@ 2001 79c978 [HomePNA] 2020 53c974 [PCscsi] 2040 79c974 - 7006 IronGate Host - 7403 Viper Power Management - 7408 Viper ISA - 7409 Viper IDE - 740B Viper ACPI - 740C Viper USB + 7006 AMD-751 [Irongate] System Controller + 7007 AMD-751 [Irongate] AGP Bridge + 7400 AMD-755 [Cobra] ISA + 7401 AMD-755 [Cobra] IDE + 7403 AMD-755 [Cobra] ACPI + 7404 AMD-755 [Cobra] USB + 7408 AMD-756 [Viper] ISA + 7409 AMD-756 [Viper] IDE + 740b AMD-756 [Viper] ACPI + 740c AMD-756 [Viper] USB 1023 Trident Microsystems 0194 82C194 2000 4DWave DX @@ -682,6 +686,7 @@ fe03 12C01A FireWire Host Controller 104d Sony Corporation 8039 CXD3222 iLINK Controller + 8056 Rockwell HCF 56K modem 104e Oak Technology, Inc 0017 OTI-64017 0107 OTI-107 [Spitfire] @@ -829,8 +834,10 @@ 1022 ISP1022 1080 ISP1080 1240 ISP1240 + 1280 ISP1280 2020 ISP2020A 2100 ISP2100 + 2200 ISP2200 1078 Cyrix Corporation 0000 5510 [Grappa] 0001 PCI Master @@ -931,6 +938,16 @@ 1330 PCI-6031E 1350 PCI-6071E 2a60 PCI-6023E + b001 IMAQ-PCI-1408 + b011 IMAQ-PXI-1408 + b021 IMAQ-PCI-1424 + b031 IMAQ-PCI-1413 + b041 IMAQ-PCI-1407 + b051 IMAQ-PXI-1407 + b061 IMAQ-PCI-1411 + b071 IMAQ-PCI-1422 + b081 IMAQ-PXI-1422 + b091 IMAQ-PXI-1411 c801 PCI-GPIB 1094 First International Computers [FIC] 1095 CMD Technology Inc @@ -2217,6 +2234,7 @@ 127a 1005 PCI56RVP Modem 13df 1005 PCI56RVP Modem 1436 1005 WS-5614PS3G + 2005 HCF 56k V90 FaxModem 8234 RapidFire 616X ATM155 Adapter 127b Pixera Corporation 127c Crosspoint Solutions, Inc. @@ -3121,6 +3139,7 @@ 0005 Permedia 0006 GLINT MX 0007 3D Extreme + 0008 GLINT Gamma G1 0009 Permedia II 2D+3D 3d3d 0100 AccelStar II 3D Accelerator 3d3d 0111 Permedia 3:16 @@ -3130,6 +3149,7 @@ 3d3d 0120 Santa Ana PCL 3d3d 0125 Oxygen VX1 3d3d 0127 Permedia3 Create! + 000a GLINT R3 0100 Permedia II 2D+3D 1004 Permedia 3d04 Permedia @@ -3309,7 +3329,7 @@ 0e11 b0dd NC3131 0e11 b0de NC3132 0e11 b0e1 NC3133 - 1014 005c Ethernet Pro 10/100 + 1014 005c 82558B Ethernet Pro 10/100 1014 105c Netfinity 10/100 1033 8000 PC-9821X-B06 1033 8016 PK-UG-X006 @@ -3363,13 +3383,13 @@ 103c 10C7 MegaRaid T5 1111 1111 MegaRaid 466 113c 03A2 MegaRaid - 2410 82801 82810 Chipset ISA Bridge (LPC) - 2411 82801 82810 Chipset IDE - 2412 82801 82810 Chipset USB - 2413 82801 82810 Chipset SMBus - 2415 82801 82810 AC'97 Audio - 2416 82801 82810 AC'97 Modem - 2418 82801 82810 PCI Bridge + 2410 82801AA 82810 Chipset ISA Bridge (LPC) + 2411 82801AA 82810 Chipset IDE + 2412 82801AA 82810 Chipset USB + 2413 82801AA 82810 Chipset SMBus + 2415 82801AA 82810 AC'97 Audio + 2416 82801AA 82810 AC'97 Modem + 2418 82801AA 82810 PCI Bridge 2420 82801AB 82810 Chipset ISA Bridge (LPC) 2421 82801AB 82810 Chipset IDE 2422 82801AB 82810 Chipset USB @@ -3392,6 +3412,8 @@ 7121 82810 CGC [Chipset Graphics Controller] 7122 82810-DC100 GMCH [Graphics Memory Controller Hub] 7123 82810-DC100 CGC [Chipset Graphics Controller] + 7124 82810E GMCH [Graphics Memory Controller Hub] + 7125 82810E CGC [Chipset Graphics Controller] 7180 440LX/EX - 82443LX/EX Host bridge 7181 440LX/EX - 82443LX/EX AGP bridge 7190 440BX/ZX - 82443BX/ZX Host bridge diff -u --recursive --new-file v2.3.42/linux/drivers/pci/pcisyms.c linux/drivers/pci/pcisyms.c --- v2.3.42/linux/drivers/pci/pcisyms.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/pci/pcisyms.c Mon Feb 7 09:29:58 2000 @@ -3,7 +3,7 @@ * * PCI Bus Services -- Exported Symbols * - * Copyright 1998 Martin Mares + * Copyright 1998--2000 Martin Mares */ #include @@ -29,6 +29,7 @@ EXPORT_SYMBOL(pci_register_driver); EXPORT_SYMBOL(pci_unregister_driver); EXPORT_SYMBOL(pci_match_device); +EXPORT_SYMBOL(pci_find_parent_resource); #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pci_setup_device); diff -u --recursive --new-file v2.3.42/linux/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c --- v2.3.42/linux/drivers/pcmcia/bulkmem.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/pcmcia/bulkmem.c Mon Feb 7 09:51:43 2000 @@ -62,7 +62,7 @@ static int do_mtd_request(memory_handle_t handle, mtd_request_t *req, caddr_t buf) { - int ret, tries; + int ret=0, tries; client_t *mtd; socket_info_t *s; diff -u --recursive --new-file v2.3.42/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- v2.3.42/linux/drivers/pcmcia/cs.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/pcmcia/cs.c Tue Feb 8 11:32:18 2000 @@ -62,10 +62,8 @@ #include "cs_internal.h" #include "rsrc_mgr.h" -#ifdef CONFIG_APM -#include -static int handle_apm_event(apm_event_t event); -#endif +#include +static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data); #ifdef PCMCIA_DEBUG int pc_debug = PCMCIA_DEBUG; @@ -84,13 +82,13 @@ #else #define CB_OPT "" #endif -#ifdef CONFIG_APM +#if defined(CONFIG_APM) || defined(CONFIG_ACPI) #define APM_OPT " [apm]" #else #define APM_OPT "" #endif #if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && \ - !defined(CONFIG_APM) + !defined(CONFIG_APM) && !defined(CONFIG_ACPI) #define OPTIONS " none" #else #define OPTIONS PCI_OPT CB_OPT APM_OPT @@ -126,9 +124,11 @@ static int io_speed = 0; /* ns */ /* Optional features */ -#ifdef CONFIG_APM +#if defined(CONFIG_APM) || defined(CONFIG_ACPI) static int do_apm = 1; MODULE_PARM(do_apm, "i"); +#else +static int do_apm = 0; #endif MODULE_PARM(setup_delay, "i"); @@ -678,22 +678,14 @@ ======================================================================*/ -#ifdef CONFIG_APM -static int handle_apm_event(apm_event_t event) +static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data) { int i, stat; socket_info_t *s; - static int down = 0; - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: + switch (rqst) { + case PM_SUSPEND: DEBUG(1, "cs: received suspend notification\n"); - if (down) { - printk(KERN_DEBUG "cs: received extra suspend event\n"); - break; - } - down = 1; for (i = 0; i < sockets; i++) { s = socket_table[i]; if ((s->state & SOCKET_PRESENT) && @@ -704,14 +696,8 @@ } } break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: + case PM_RESUME: DEBUG(1, "cs: received resume notification\n"); - if (!down) { - printk(KERN_DEBUG "cs: received bogus resume event\n"); - break; - } - down = 0; for (i = 0; i < sockets; i++) { s = socket_table[i]; /* Do this just to reinitialize the socket */ @@ -725,8 +711,7 @@ break; } return 0; -} /* handle_apm_event */ -#endif +} /* handle_pm_event */ /*====================================================================== @@ -2287,23 +2272,32 @@ OS-specific module glue goes here ======================================================================*/ +/* in alpha order */ EXPORT_SYMBOL(pcmcia_access_configuration_register); EXPORT_SYMBOL(pcmcia_adjust_resource_info); +EXPORT_SYMBOL(pcmcia_bind_device); +EXPORT_SYMBOL(pcmcia_bind_mtd); EXPORT_SYMBOL(pcmcia_check_erase_queue); EXPORT_SYMBOL(pcmcia_close_memory); EXPORT_SYMBOL(pcmcia_copy_memory); EXPORT_SYMBOL(pcmcia_deregister_client); EXPORT_SYMBOL(pcmcia_deregister_erase_queue); +EXPORT_SYMBOL(pcmcia_eject_card); EXPORT_SYMBOL(pcmcia_get_first_client); EXPORT_SYMBOL(pcmcia_get_card_services_info); EXPORT_SYMBOL(pcmcia_get_configuration_info); +EXPORT_SYMBOL(pcmcia_get_mem_page); EXPORT_SYMBOL(pcmcia_get_next_client); EXPORT_SYMBOL(pcmcia_get_first_region); EXPORT_SYMBOL(pcmcia_get_first_tuple); +EXPORT_SYMBOL(pcmcia_get_first_window); EXPORT_SYMBOL(pcmcia_get_next_region); EXPORT_SYMBOL(pcmcia_get_next_tuple); +EXPORT_SYMBOL(pcmcia_get_next_window); EXPORT_SYMBOL(pcmcia_get_status); EXPORT_SYMBOL(pcmcia_get_tuple_data); +EXPORT_SYMBOL(pcmcia_insert_card); +EXPORT_SYMBOL(pcmcia_lookup_bus); EXPORT_SYMBOL(pcmcia_map_mem_page); EXPORT_SYMBOL(pcmcia_modify_configuration); EXPORT_SYMBOL(pcmcia_modify_window); @@ -2317,26 +2311,20 @@ EXPORT_SYMBOL(pcmcia_release_io); EXPORT_SYMBOL(pcmcia_release_irq); EXPORT_SYMBOL(pcmcia_release_window); +EXPORT_SYMBOL(pcmcia_replace_cis); +EXPORT_SYMBOL(pcmcia_report_error); EXPORT_SYMBOL(pcmcia_request_configuration); EXPORT_SYMBOL(pcmcia_request_io); EXPORT_SYMBOL(pcmcia_request_irq); EXPORT_SYMBOL(pcmcia_request_window); EXPORT_SYMBOL(pcmcia_reset_card); +EXPORT_SYMBOL(pcmcia_resume_card); EXPORT_SYMBOL(pcmcia_set_event_mask); +EXPORT_SYMBOL(pcmcia_suspend_card); EXPORT_SYMBOL(pcmcia_validate_cis); EXPORT_SYMBOL(pcmcia_write_memory); -EXPORT_SYMBOL(pcmcia_bind_device); -EXPORT_SYMBOL(pcmcia_bind_mtd); -EXPORT_SYMBOL(pcmcia_report_error); -EXPORT_SYMBOL(pcmcia_suspend_card); -EXPORT_SYMBOL(pcmcia_resume_card); -EXPORT_SYMBOL(pcmcia_eject_card); -EXPORT_SYMBOL(pcmcia_insert_card); -EXPORT_SYMBOL(pcmcia_replace_cis); -EXPORT_SYMBOL(pcmcia_get_first_window); -EXPORT_SYMBOL(pcmcia_get_next_window); -EXPORT_SYMBOL(pcmcia_get_mem_page); +EXPORT_SYMBOL(dead_socket); EXPORT_SYMBOL(register_ss_entry); EXPORT_SYMBOL(unregister_ss_entry); EXPORT_SYMBOL(CardServices); @@ -2353,10 +2341,8 @@ #endif printk(KERN_INFO " %s\n", options); DEBUG(0, "%s\n", version); -#ifdef CONFIG_APM if (do_apm) - apm_register_callback(&handle_apm_event); -#endif + pm_register(PM_SYS_DEV, PM_SYS_PCMCIA, handle_pm_event); #ifdef CONFIG_PROC_FS proc_pccard = proc_mkdir("pccard", proc_bus); #endif @@ -2371,10 +2357,8 @@ remove_proc_entry("pccard", proc_bus); } #endif -#ifdef CONFIG_APM if (do_apm) - apm_unregister_callback(&handle_apm_event); -#endif + pm_unregister_all(handle_pm_event); release_resource_db(); } diff -u --recursive --new-file v2.3.42/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c --- v2.3.42/linux/drivers/pcmcia/ds.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/pcmcia/ds.c Wed Feb 9 11:42:35 2000 @@ -853,12 +853,12 @@ /*====================================================================*/ static struct file_operations ds_fops = { - open: ds_open, - release: ds_release, - ioctl: ds_ioctl, - read: ds_read, - write: ds_write, - poll: ds_poll + open: ds_open, + release: ds_release, + ioctl: ds_ioctl, + read: ds_read, + write: ds_write, + poll: ds_poll, }; EXPORT_SYMBOL(register_pccard_driver); diff -u --recursive --new-file v2.3.42/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.3.42/linux/drivers/pcmcia/yenta.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/pcmcia/yenta.c Mon Feb 7 09:52:18 2000 @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -739,6 +740,7 @@ yenta_set_mem_map, yenta_proc_setup }; +EXPORT_SYMBOL(yenta_operations); /* * Ricoh cardbus bridge: standard cardbus, except it needs diff -u --recursive --new-file v2.3.42/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.3.42/linux/drivers/pnp/isapnp.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/pnp/isapnp.c Mon Feb 7 09:51:43 2000 @@ -241,7 +241,7 @@ static void __init isapnp_peek(unsigned char *data, int bytes) { int i, j; - unsigned char d; + unsigned char d=0; for (i = 1; i <= bytes; i++) { for (j = 0; j < 10; j++) { diff -u --recursive --new-file v2.3.42/linux/drivers/pnp/isapnp_proc.c linux/drivers/pnp/isapnp_proc.c --- v2.3.42/linux/drivers/pnp/isapnp_proc.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/pnp/isapnp_proc.c Wed Feb 9 11:42:35 2000 @@ -202,19 +202,12 @@ static struct file_operations isapnp_info_entry_operations = { - isapnp_info_entry_lseek, /* lseek */ - isapnp_info_entry_read, /* read */ - isapnp_info_entry_write, /* write */ - NULL, /* readdir */ - isapnp_info_entry_poll, /* poll */ - NULL, /* ioctl - default */ - NULL, /* mmap */ - isapnp_info_entry_open, /* open */ - NULL, /* flush */ - isapnp_info_entry_release, /* release */ - NULL, /* can't fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: isapnp_info_entry_lseek, + read: isapnp_info_entry_read, + write: isapnp_info_entry_write, + poll: isapnp_info_entry_poll, + open: isapnp_info_entry_open, + release: isapnp_info_entry_release, }; static struct inode_operations isapnp_info_entry_inode_operations = @@ -277,19 +270,8 @@ static struct file_operations isapnp_proc_bus_file_operations = { - isapnp_proc_bus_lseek, /* lseek */ - isapnp_proc_bus_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl - default */ - NULL, /* mmap */ - NULL, /* open */ - NULL, /* flush */ - NULL, /* release */ - NULL, /* can't fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: isapnp_proc_bus_lseek, + read: isapnp_proc_bus_read, }; static struct inode_operations isapnp_proc_bus_inode_operations = diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/audio/Config.in linux/drivers/sbus/audio/Config.in --- v2.3.42/linux/drivers/sbus/audio/Config.in Mon Nov 1 13:56:26 1999 +++ linux/drivers/sbus/audio/Config.in Tue Feb 8 18:23:13 2000 @@ -4,6 +4,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + mainmenu_option next_comment comment 'Linux/SPARC audio subsystem (EXPERIMENTAL)' tristate 'Audio support (EXPERIMENTAL)' CONFIG_SPARCAUDIO @@ -11,4 +12,5 @@ dep_tristate ' CS4231 Lowlevel Driver' CONFIG_SPARCAUDIO_CS4231 $CONFIG_SPARCAUDIO dep_tristate ' DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO dep_tristate ' Dummy Lowlevel Driver' CONFIG_SPARCAUDIO_DUMMY $CONFIG_SPARCAUDIO + endmenu fi diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.3.42/linux/drivers/sbus/audio/audio.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/sbus/audio/audio.c Wed Feb 9 19:39:04 2000 @@ -1,4 +1,4 @@ -/* $Id: audio.c,v 1.47 1999/12/15 22:30:16 davem Exp $ +/* $Id: audio.c,v 1.48 2000/02/09 22:33:19 davem Exp $ * drivers/sbus/audio/audio.c * * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) @@ -1959,18 +1959,9 @@ #endif static struct file_operations sparcaudioctl_fops = { - NULL, - NULL, - NULL, - NULL, /* sparcaudio_readdir */ - sparcaudio_select, - sparcaudio_ioctl, - NULL, /* sparcaudio_mmap */ - NULL, -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff - NULL, /* sparcaudio_flush */ -#endif - sparcaudioctl_release, + poll: sparcaudio_select, + ioctl: sparcaudio_ioctl, + release: sparcaudioctl_release, }; static int sparcaudio_open(struct inode * inode, struct file * file) @@ -2170,18 +2161,13 @@ #endif static struct file_operations sparcaudio_fops = { - sparcaudio_lseek, - sparcaudio_read, - sparcaudio_write, - NULL, /* sparcaudio_readdir */ - sparcaudio_select, - sparcaudio_ioctl, - NULL, /* sparcaudio_mmap */ - sparcaudio_open, -#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff - NULL, /* sparcaudio_flush */ -#endif - sparcaudio_release + llseek: sparcaudio_lseek, + read: sparcaudio_read, + write: sparcaudio_write, + poll: sparcaudio_select, + ioctl: sparcaudio_ioctl, + open: sparcaudio_open, + release: sparcaudio_release, }; #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x20100 diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in --- v2.3.42/linux/drivers/sbus/char/Config.in Wed Dec 29 13:13:17 1999 +++ linux/drivers/sbus/char/Config.in Tue Feb 8 18:23:13 2000 @@ -1,3 +1,4 @@ +mainmenu_option next_comment comment 'Misc Linux/SPARC drivers' tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC @@ -12,12 +13,16 @@ tristate 'Bidirectional parallel port support (OBSOLETE)' CONFIG_SUN_BPP tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA - tristate 'Tadpole TS102 Microcontroller support (EXPERIMENTAL)' CONFIG_TADPOLE_TS102_UCTRL - tristate 'JavaStation OS Flash SIMM (EXPERIMENTAL)' CONFIG_SUN_JSFLASH - # XXX Why don't we do "source drivers/char/Config.in" somewhere? - if [ "$CONFIG_PCI" = "y" ]; then - define_bool CONFIG_APM_RTC_IS_GMT y # no shit - bool 'PC-style RTC' CONFIG_RTC + if [ "$ARCH" = "sparc" ]; then + tristate 'Tadpole TS102 Microcontroller support (EXPERIMENTAL)' CONFIG_TADPOLE_TS102_UCTRL + + tristate 'JavaStation OS Flash SIMM (EXPERIMENTAL)' CONFIG_SUN_JSFLASH + # XXX Why don't we do "source drivers/char/Config.in" somewhere? + if [ "$CONFIG_PCI" = "y" ]; then + define_bool CONFIG_APM_RTC_IS_GMT y # no shit + bool 'PC-style RTC' CONFIG_RTC + fi fi fi +endmenu diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c --- v2.3.42/linux/drivers/sbus/char/bpp.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sbus/char/bpp.c Wed Feb 9 11:42:35 2000 @@ -834,19 +834,11 @@ } static struct file_operations bpp_fops = { - NULL, /* bpp_lseek */ - bpp_read, - bpp_write, - NULL, /* bpp_readdir */ - NULL, /* bpp_select */ - bpp_ioctl, - NULL, /* bpp_mmap */ - bpp_open, - NULL, /* flush */ - bpp_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + read: bpp_read, + write: bpp_write, + ioctl: bpp_ioctl, + open: bpp_open, + release: bpp_release, }; #if defined(__i386__) diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c --- v2.3.42/linux/drivers/sbus/char/envctrl.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/sbus/char/envctrl.c Wed Feb 9 19:39:04 2000 @@ -1,4 +1,4 @@ -/* $Id: envctrl.c,v 1.14 2000/01/09 15:43:45 ecd Exp $ +/* $Id: envctrl.c,v 1.15 2000/02/09 22:33:23 davem Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -1522,16 +1522,12 @@ } static struct file_operations envctrl_fops = { - envctrl_llseek, - envctrl_read, - envctrl_write, - NULL, /* readdir */ - NULL, /* poll */ - envctrl_ioctl, - NULL, /* mmap */ - envctrl_open, - NULL, /* flush */ - envctrl_release + llseek: envctrl_llseek, + read: envctrl_read, + write: envctrl_write, + ioctl: envctrl_ioctl, + open: envctrl_open, + release: envctrl_release, }; static struct miscdevice envctrl_dev = { diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c --- v2.3.42/linux/drivers/sbus/char/flash.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/sbus/char/flash.c Thu Feb 10 12:16:38 2000 @@ -1,4 +1,4 @@ -/* $Id: flash.c,v 1.15 1999/12/09 00:44:22 davem Exp $ +/* $Id: flash.c,v 1.17 2000/02/10 02:51:35 davem Exp $ * flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -128,18 +128,14 @@ } static struct file_operations flash_fops = { - flash_llseek, - flash_read, - NULL, /* no write to the Flash, use mmap - * and play flash dependent tricks. - */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - flash_mmap, - flash_open, - NULL, /* flush */ - flash_release + /* no write to the Flash, use mmap + * and play flash dependent tricks. + */ + llseek: flash_llseek, + read: flash_read, + mmap: flash_mmap, + open: flash_open, + release: flash_release, }; static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/jsflash.c linux/drivers/sbus/char/jsflash.c --- v2.3.42/linux/drivers/sbus/char/jsflash.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sbus/char/jsflash.c Wed Feb 9 11:42:35 2000 @@ -30,6 +30,7 @@ #include #include #include +#include #if 0 /* P3 from mem.c */ #include #include @@ -47,6 +48,8 @@ #include #include #endif +#include +#include #include /* ioctl arguments. ?? */ #define JSFIDSZ (sizeof(struct jsflash_ident_arg)) @@ -357,17 +360,13 @@ } static struct file_operations jsf_fops = { - jsf_lseek, - jsf_read, - jsf_write, - NULL, /* readdir */ - NULL, /* poll */ - jsf_ioctl, - jsf_mmap, - jsf_open, - NULL, /* flush */ - jsf_release, - NULL /* fsync */ + llseek: jsf_lseek, + read: jsf_read, + write: jsf_write, + ioctl: jsf_ioctl, + mmap: jsf_mmap, + open: jsf_open, + release: jsf_release, }; static struct miscdevice jsf_dev = { JSF_MINOR, "jsflash", &jsf_fops }; @@ -377,10 +376,16 @@ #ifdef MODULE int init_module(void) #else -int /* __init */ jsflash_init(void) +int __init jsflash_init(void) #endif { int rc; + char banner[128]; + + /* FIXME: Really autodetect things */ + prom_getproperty(prom_root_node, "banner-name", banner, 128); + if (strcmp (banner, "JavaStation-NC") && strcmp (banner, "JavaStation-E")) + return -ENXIO; /* extern enum sparc_cpu sparc_cpu_model; */ /* in */ if (sparc_cpu_model == sun4m && jsf0.base == 0) { diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c --- v2.3.42/linux/drivers/sbus/char/openprom.c Wed Dec 29 13:13:17 1999 +++ linux/drivers/sbus/char/openprom.c Wed Feb 9 11:42:35 2000 @@ -608,16 +608,10 @@ } static struct file_operations openprom_fops = { - openprom_lseek, - NULL, /* openprom_read */ - NULL, /* openprom_write */ - NULL, /* openprom_readdir */ - NULL, /* openprom_poll */ - openprom_ioctl, - NULL, /* openprom_mmap */ - openprom_open, - NULL, /* flush */ - openprom_release + llseek: openprom_lseek, + ioctl: openprom_ioctl, + open: openprom_open, + release: openprom_release, }; static struct miscdevice openprom_dev = { diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.3.42/linux/drivers/sbus/char/pcikbd.c Tue Jan 11 22:31:41 2000 +++ linux/drivers/sbus/char/pcikbd.c Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.41 2000/01/08 07:01:20 davem Exp $ +/* $Id: pcikbd.c,v 1.43 2000/02/09 22:33:25 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -325,7 +326,7 @@ handle_scancode(scancode, !(scancode & 0x80)); status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while(status & KBD_STAT_OBF); - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); } static int send_data(unsigned char data) @@ -713,12 +714,13 @@ static inline void aux_start_atomic(void) { down(&aux_sema4); - disable_bh(KEYBOARD_BH); + tasklet_disable_nosync(&keyboard_tasklet); + tasklet_unlock_wait(&keyboard_tasklet); } static inline void aux_end_atomic(void) { - enable_bh(KEYBOARD_BH); + tasklet_enable(&keyboard_tasklet); up(&aux_sema4); } @@ -889,18 +891,12 @@ } struct file_operations psaux_fops = { - NULL, /* seek */ - aux_read, - aux_write, - NULL, /* readdir */ - aux_poll, - NULL, /* ioctl */ - NULL, /* mmap */ - aux_open, - NULL, /* flush */ - aux_release, - NULL, - aux_fasync, + read: aux_read, + write: aux_write, + poll: aux_poll, + open: aux_open, + release: aux_release, + fasync: aux_fasync, }; static int aux_no_open(struct inode *inode, struct file *file) @@ -909,14 +905,7 @@ } struct file_operations psaux_no_fops = { - NULL, /* seek */ - NULL, - NULL, - NULL, /* readdir */ - NULL, - NULL, /* ioctl */ - NULL, /* mmap */ - aux_no_open, + open: aux_no_open, }; static struct miscdevice psaux_mouse = { @@ -1035,6 +1024,9 @@ goto found; } #endif + if (!pci_present()) + goto do_enodev; + /* * Get the nodes for keyboard and mouse from aliases on normal systems. */ diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.3.42/linux/drivers/sbus/char/rtc.c Fri Sep 10 23:57:30 1999 +++ linux/drivers/sbus/char/rtc.c Wed Feb 9 19:39:04 2000 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.18 1999/08/31 18:51:36 davem Exp $ +/* $Id: rtc.c,v 1.19 2000/02/09 22:33:26 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -137,16 +137,10 @@ } static struct file_operations rtc_fops = { - rtc_lseek, - NULL, /* rtc_read */ - NULL, /* rtc_write */ - NULL, /* rtc_readdir */ - NULL, /* rtc_poll */ - rtc_ioctl, - NULL, /* rtc_mmap */ - rtc_open, - NULL, /* flush */ - rtc_release + llseek: rtc_lseek, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, }; static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.3.42/linux/drivers/sbus/char/su.c Wed Dec 29 13:13:18 1999 +++ linux/drivers/sbus/char/su.c Wed Feb 9 19:39:04 2000 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.34 1999/12/02 09:55:21 davem Exp $ +/* $Id: su.c,v 1.36 2000/02/09 21:11:22 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2223,7 +2223,7 @@ */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.34 $"; + char *revision = "$Revision: 1.36 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c --- v2.3.42/linux/drivers/sbus/char/sunkbd.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sbus/char/sunkbd.c Wed Feb 9 20:08:09 2000 @@ -243,19 +243,13 @@ #define KEY_ALT 0x86 #define KEY_L1 0x87 -/* Do to sun_kbd_init() being called before rs_init(), and sun_kbd_init() doing: +/* Due to sun_kbd_init() being called before rs_init(), and sun_kbd_init() doing: * - * init_bh(KEYBOARD_BH, kbd_bh); - * mark_bh(KEYBOARD_BH); + * tasklet_enable(&keyboard_tasklet); + * tasklet_schedule(&keyboard_tasklet); * * this might well be called before some driver has claimed interest in * handling the keyboard input/output. So we need to assign an initial nop. - * - * Otherwise this would lead to the following (DaveM might want to look at): - * - * sparc64_dtlb_refbit_catch(), - * do_sparc64_fault(), - * kernel NULL pointer dereference at do_sparc64_fault + 0x2c0 ;-( */ static void nop_kbd_put_char(unsigned char c) { } static void (*kbd_put_char)(unsigned char) = nop_kbd_put_char; @@ -460,6 +454,10 @@ restore_flags(flags); } +#ifndef CONFIG_PCI +DECLARE_TASKLET_DISABLED(keyboard_tasklet, sun_kbd_bh, 0); +#endif + /* #define SKBD_DEBUG */ /* This is our keyboard 'interrupt' routine. */ void sunkbd_inchar(unsigned char ch, struct pt_regs *regs) @@ -610,7 +608,7 @@ } } out: - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); } static void put_queue(int ch) @@ -1086,7 +1084,6 @@ */ static unsigned char ledstate = 0xff; /* undefined */ -static unsigned char sunkbd_ledstate = 0xff; /* undefined */ static unsigned char ledioctl; unsigned char sun_getledstate(void) { @@ -1163,7 +1160,8 @@ * used, but this allows for easy and efficient race-condition * prevention later on. */ -static void kbd_bh(void) +static unsigned char sunkbd_ledstate = 0xff; /* undefined */ +void sun_kbd_bh(unsigned long dummy) { unsigned char leds = getleds(); unsigned char kbd_leds = vcleds_to_sunkbd(leds); @@ -1247,8 +1245,12 @@ } else { sunkbd_clickp = 0; } - init_bh(KEYBOARD_BH, kbd_bh); - mark_bh(KEYBOARD_BH); + + keyboard_tasklet.func = sun_kbd_bh; + + tasklet_enable(&keyboard_tasklet); + tasklet_schedule(&keyboard_tasklet); + return 0; } @@ -1486,21 +1488,14 @@ return 0; } -static struct -file_operations kbd_fops = +static struct file_operations kbd_fops = { - NULL, /* seek */ - kbd_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - kbd_poll, /* poll */ - kbd_ioctl, /* ioctl */ - NULL, /* mmap */ - kbd_open, /* open */ - NULL, /* flush */ - kbd_close, /* close */ - NULL, /* fsync */ - kbd_fasync, /* fasync */ + read: kbd_read, + poll: kbd_poll, + ioctl: kbd_ioctl, + open: kbd_open, + release: kbd_close, + fasync: kbd_fasync, }; void __init keyboard_zsinit(void (*put_char)(unsigned char)) diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/sunkbd.h linux/drivers/sbus/char/sunkbd.h --- v2.3.42/linux/drivers/sbus/char/sunkbd.h Mon Jan 12 15:15:45 1998 +++ linux/drivers/sbus/char/sunkbd.h Wed Feb 9 20:08:09 2000 @@ -1,4 +1,4 @@ -/* $Id: sunkbd.h,v 1.3 1997/09/08 03:05:10 tdyas Exp $ +/* $Id: sunkbd.h,v 1.4 2000/02/09 11:15:54 davem Exp $ * sunkbd.h: Defines needed by SUN Keyboard drivers * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -26,6 +26,7 @@ extern void sunkbd_inchar(unsigned char, struct pt_regs *); extern void batten_down_hatches(void); +extern void sun_kbd_bh(unsigned long); extern int sun_kbd_init(void); extern void sun_compute_shiftstate(void); extern void sun_setledstate(struct kbd_struct *, unsigned int); diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c --- v2.3.42/linux/drivers/sbus/char/sunmouse.c Wed Dec 29 13:13:18 1999 +++ linux/drivers/sbus/char/sunmouse.c Wed Feb 9 11:42:35 2000 @@ -542,18 +542,13 @@ } struct file_operations sun_mouse_fops = { - NULL, - sun_mouse_read, - sun_mouse_write, - NULL, - sun_mouse_poll, - sun_mouse_ioctl, - NULL, - sun_mouse_open, - NULL, /* flush */ - sun_mouse_close, - NULL, - sun_mouse_fasync, + read: sun_mouse_read, + write: sun_mouse_write, + poll: sun_mouse_poll, + ioctl: sun_mouse_ioctl, + open: sun_mouse_open, + release: sun_mouse_close, + fasync: sun_mouse_fasync, }; static struct miscdevice sun_mouse_mouse = { diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/uctrl.c linux/drivers/sbus/char/uctrl.c --- v2.3.42/linux/drivers/sbus/char/uctrl.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sbus/char/uctrl.c Wed Feb 9 19:39:04 2000 @@ -1,4 +1,4 @@ -/* $Id: uctrl.c,v 1.6 2000/01/22 05:22:07 anton Exp $ +/* $Id: uctrl.c,v 1.7 2000/02/09 22:33:28 davem Exp $ * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3 * * Copyright 1999 Derrick J Brashear (shadow@dementia.org) @@ -238,16 +238,10 @@ } static struct file_operations uctrl_fops = { - uctrl_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - uctrl_ioctl, - NULL, /* mmap */ - uctrl_open, - NULL, /* flush */ - uctrl_release + llseek: uctrl_llseek, + ioctl: uctrl_ioctl, + open: uctrl_open, + release: uctrl_release, }; static struct miscdevice uctrl_dev = { diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.3.42/linux/drivers/sbus/char/vfc_dev.c Wed Dec 29 13:13:18 1999 +++ linux/drivers/sbus/char/vfc_dev.c Wed Feb 9 11:42:35 2000 @@ -627,16 +627,11 @@ } static struct file_operations vfc_fops = { - vfc_lseek, /* vfc_lseek */ - NULL, /* vfc_write */ - NULL, /* vfc_read */ - NULL, /* vfc_readdir */ - NULL, /* vfc_select */ - vfc_ioctl, - vfc_mmap, - vfc_open, - NULL, /* flush */ - vfc_release, + llseek: vfc_lseek, + ioctl: vfc_ioctl, + mmap: vfc_mmap, + open: vfc_open, + release: vfc_release, }; static int vfc_probe(void) diff -u --recursive --new-file v2.3.42/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.3.42/linux/drivers/sbus/char/zs.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/sbus/char/zs.c Wed Feb 9 19:39:04 2000 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.53 2000/01/29 01:29:38 anton Exp $ +/* $Id: zs.c,v 1.55 2000/02/09 21:11:24 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1928,7 +1928,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.53 $"; + char *revision = "$Revision: 1.55 $"; char *version, *p; version = strchr(revision, ' '); diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.3.42/linux/drivers/scsi/Config.in Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/Config.in Wed Feb 9 18:40:23 2000 @@ -1,10 +1,22 @@ comment 'SCSI support type (disk, tape, CD-ROM)' dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + +if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then + int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 +fi + dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + +if [ "$CONFIG_BLK_DEV_ST" != "n" ]; then + int 'Maximum number of SCSI tapes that can be loaded as modules' CONFIG_ST_EXTRA_DEVS 2 +fi + dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI + if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 fi dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI @@ -126,6 +138,7 @@ if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI + dep_tristate 'Qlogic QLA 1280 SCSI support' CONFIG_SCSI_QLOGIC_1280 $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.3.42/linux/drivers/scsi/Makefile Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/Makefile Mon Feb 7 19:45:28 2000 @@ -322,6 +322,14 @@ endif endif +ifeq ($(CONFIG_SCSI_QLOGIC_1280),y) +L_OBJS += qla1280.o +else + ifeq ($(CONFIG_SCSI_QLOGIC_1280),m) + M_OBJS += qla1280.o + endif +endif + ifeq ($(CONFIG_SCSI_ACARD),y) L_OBJS += atp870u.o else diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.3.42/linux/drivers/scsi/advansys.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/scsi/advansys.c Wed Feb 9 18:40:23 2000 @@ -10505,8 +10505,8 @@ (ulong) s->host_queue, (ulong) s->hostt, (ulong) s->block); printk( -" wish_block %d, base %lu, io_port %lu, n_io_port %u, irq %d,\n", - s->wish_block, (ulong) s->base, (ulong) s->io_port, s->n_io_port, +" base %lu, io_port %lu, n_io_port %u, irq %d,\n", + (ulong) s->base, (ulong) s->io_port, s->n_io_port, s->irq); printk( diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.3.42/linux/drivers/scsi/eata.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/scsi/eata.c Wed Feb 9 18:40:23 2000 @@ -1049,7 +1049,7 @@ sh[j]->unchecked_isa_dma = FALSE; else { unsigned long flags; -//FIXME// sh[j]->wish_block = TRUE; + scsi_register_blocked_host(sh[j]); sh[j]->unchecked_isa_dma = TRUE; flags=claim_dma_lock(); @@ -2273,6 +2273,10 @@ if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n", driver_name); + + if( sh[j]->unchecked_isa_dma ) { + scsi_deregister_blocked_host(sh[j]); + } for (i = 0; i < sh[j]->can_queue; i++) if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v2.3.42/linux/drivers/scsi/eata_dma.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/eata_dma.c Wed Feb 9 18:40:23 2000 @@ -131,12 +131,11 @@ if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq, NULL); else reg_IRQ[sh->irq]--; - scsi_init_free((void *)status, 512); - scsi_init_free((void *)dma_scratch - 4, 1024); + kfree((void *)status); + kfree((void *)dma_scratch - 4); for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */ if(SD(sh)->ccb[i].sg_list != NULL) - scsi_init_free((void *) SD(sh)->ccb[i].sg_list, - sh->sg_tablesize * sizeof(struct eata_sg_list)); + kfree((void *) SD(sh)->ccb[i].sg_list); } if (SD(sh)->channel == 0) { @@ -908,9 +907,9 @@ static char *buff; ulong i; - cp = (struct eata_ccb *) scsi_init_malloc(sizeof(struct eata_ccb), - GFP_ATOMIC | GFP_DMA); - sp = (struct eata_sp *) scsi_init_malloc(sizeof(struct eata_sp), + cp = (struct eata_ccb *) kmalloc(sizeof(struct eata_ccb), + GFP_ATOMIC | GFP_DMA); + sp = (struct eata_sp *) kmalloc(sizeof(struct eata_sp), GFP_ATOMIC | GFP_DMA); buff = dma_scratch; @@ -954,8 +953,8 @@ fake_int_result, (u32) (sp->hba_stat /*& 0x7f*/), (u32) sp->scsi_stat, buff, sp)); - scsi_init_free((void *)cp, sizeof(struct eata_ccb)); - scsi_init_free((void *)sp, sizeof(struct eata_sp)); + kfree((void *)cp); + kfree((void *)sp); if ((fake_int_result & HA_SERROR) || time_after(jiffies, i)){ printk(KERN_WARNING "eata_dma: trying to reset HBA at %x to clear " @@ -1287,8 +1286,6 @@ else hd->primary = TRUE; -//FIXME// sh->wish_block = FALSE; - if (hd->bustype != IS_ISA) { sh->unchecked_isa_dma = FALSE; } else { @@ -1459,8 +1456,8 @@ tpnt->proc_name = "eata_dma"; - status = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); - dma_scratch = scsi_init_malloc(1024, GFP_ATOMIC | GFP_DMA); + status = kmalloc(512, GFP_ATOMIC | GFP_DMA); + dma_scratch = kmalloc(1024, GFP_ATOMIC | GFP_DMA); if(status == NULL || dma_scratch == NULL) { printk("eata_dma: can't allocate enough memory to probe for hosts !\n"); @@ -1511,10 +1508,10 @@ HBA_ptr = SD(HBA_ptr)->next; } } else { - scsi_init_free((void *)status, 512); + kfree((void *)status); } - scsi_init_free((void *)dma_scratch - 4, 1024); + kfree((void *)dma_scratch - 4); DBG(DPT_DEBUG, DELAY(12)); diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.3.42/linux/drivers/scsi/hosts.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/hosts.c Wed Feb 9 18:40:23 2000 @@ -9,6 +9,8 @@ * * * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli + * Added QLOGIC QLA1280 SCSI controller kernel host support. + * August 4, 1999 Fred Lewis, Intel DuPont */ @@ -191,6 +193,10 @@ #include "qlogicfc.h" #endif +#ifdef CONFIG_SCSI_QLOGIC_1280 +#include "qla1280.h" +#endif + #ifdef CONFIG_SCSI_SEAGATE #include "seagate.h" #endif @@ -528,6 +534,9 @@ #ifdef CONFIG_SCSI_QLOGIC_FC QLOGICFC, #endif +#ifdef CONFIG_SCSI_QLOGIC_1280 + QLA1280_LINUX_TEMPLATE, +#endif #ifdef CONFIG_SCSI_PAS16 MV_PAS16, #endif @@ -689,7 +698,7 @@ } } next_scsi_host--; - scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + sh->extra_bytes); + kfree((char *) sh); } /* We call this when we come across a new host adapter. We only do this @@ -699,8 +708,9 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){ struct Scsi_Host * retval, *shpnt; - retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j, - (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC); + retval = (struct Scsi_Host *)kmalloc(sizeof(struct Scsi_Host) + j, + (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC); + memset(retval, 0, sizeof(struct Scsi_Host) + j); atomic_set(&retval->host_active,0); retval->host_busy = 0; retval->host_failed = 0; @@ -745,7 +755,7 @@ retval->unchecked_isa_dma = tpnt->unchecked_isa_dma; retval->use_clustering = tpnt->use_clustering; - retval->select_queue_depths = NULL; + retval->select_queue_depths = tpnt->select_queue_depths; if(!scsi_hostlist) scsi_hostlist = retval; diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.3.42/linux/drivers/scsi/hosts.h Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/hosts.h Thu Feb 10 12:37:22 2000 @@ -25,6 +25,7 @@ $Header: /vger/u4/cvs/linux/drivers/scsi/hosts.h,v 1.6 1997/01/19 23:07:13 davem Exp $ */ +#include #include /* It is senseless to set SG_ALL any higher than this - the performance @@ -210,6 +211,12 @@ */ int (* bios_param)(Disk *, kdev_t, int []); + + /* + * Used to set the queue depth for a specific device. + */ + void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *); + /* * This determines if we will use a non-interrupt driven * or an interrupt driven scheme, It is set to the maximum number @@ -417,16 +424,6 @@ * scsi_init initializes the scsi hosts. */ -/* - * We use these goofy things because the MM is not set up when we init - * the scsi subsystem. By using these functions we can write code that - * looks normal. Also, it makes it possible to use the same code for a - * loadable module. - */ - -extern void * scsi_init_malloc(unsigned int size, int priority); -extern void scsi_init_free(char * ptr, unsigned int size); - extern int next_scsi_host; extern int scsi_loadable_module_flag; @@ -434,7 +431,8 @@ extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j); extern void scsi_unregister(struct Scsi_Host * i); -extern request_fn_proc * scsi_get_request_handler(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt); +extern void scsi_register_blocked_host(struct Scsi_Host * SHpnt); +extern void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt); /* * Prototypes for functions/data in scsi_scan.c @@ -473,6 +471,8 @@ Selects command for blkdevs */ }; +void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt); + extern struct Scsi_Device_Template sd_template; extern struct Scsi_Device_Template st_template; extern struct Scsi_Device_Template sr_template; @@ -499,10 +499,14 @@ * * Even bigger hack for SparcSTORAGE arrays. Those are at least 6 disks, but * usually up to 30 disks, so everyone would need to change this. -jj + * + * Note: These things are all evil and all need to go away. My plan is to + * tackle the character devices first, as there aren't any locking implications + * in the block device layer. The block devices will require more work. */ -#define SD_EXTRA_DEVS 40 -#define ST_EXTRA_DEVS 2 -#define SR_EXTRA_DEVS 2 +#define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS +#define ST_EXTRA_DEVS CONFIG_ST_EXTRA_DEVS +#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS #define SG_EXTRA_DEVS (SD_EXTRA_DEVS + SR_EXTRA_DEVS + ST_EXTRA_DEVS) #endif diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- v2.3.42/linux/drivers/scsi/ips.c Mon Dec 20 18:48:22 1999 +++ linux/drivers/scsi/ips.c Wed Feb 9 18:40:23 2000 @@ -459,7 +459,6 @@ sh->cmd_per_lun = sh->hostt->cmd_per_lun; sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; sh->use_clustering = sh->hostt->use_clustering; -//FIXME// sh->wish_block = FALSE; /* Store info in HA structure */ ha->io_addr = io_addr; diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c --- v2.3.42/linux/drivers/scsi/mesh.c Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/mesh.c Wed Feb 9 19:43:57 2000 @@ -253,7 +253,7 @@ continue; } mesh_host->unique_id = nmeshes; -#ifndef MODULE +#if !defined(MODULE) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)) note_scsi_host(mesh, mesh_host); #endif @@ -305,7 +305,9 @@ if (mesh_sync_period < minper) mesh_sync_period = minper; +#if defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) feature_set(mesh, FEATURE_MESH_enable); +#endif mdelay(200); mesh_init(ms); diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/pluto.c linux/drivers/scsi/pluto.c --- v2.3.42/linux/drivers/scsi/pluto.c Wed Dec 29 13:13:18 1999 +++ linux/drivers/scsi/pluto.c Wed Feb 9 18:40:23 2000 @@ -112,7 +112,7 @@ #endif return 0; } - fcs = (struct ctrl_inquiry *) scsi_init_malloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA); + fcs = (struct ctrl_inquiry *) kmalloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA); if (!fcs) { printk ("PLUTO: Not enough memory to probe\n"); return 0; @@ -265,7 +265,7 @@ } else fc->fcp_register(fc, TYPE_SCSI_FCP, 1); } - scsi_init_free((char *)fcs, sizeof (struct ctrl_inquiry) * fcscount); + kfree((char *)fcs); if (nplutos) printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos); return nplutos; diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/ql12160_fw.h linux/drivers/scsi/ql12160_fw.h --- v2.3.42/linux/drivers/scsi/ql12160_fw.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/ql12160_fw.h Mon Feb 7 19:45:28 2000 @@ -0,0 +1,1704 @@ +/* + ************************************************************************ + * * + * --- ISP12160 Initiator Firmware --- * + * 32 LUN Support * + * * + ************************************************************************ + * * + * Copyright (C) 1999,2000 Qlogic, Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted provided + * that the following conditions are met: + * 1. Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + * * + ************************************************************************ + */ + + +/* + * Firmware Version 10.01.19 (12:38 Oct 12, 1999) + */ + +#ifdef UNIQUE_FW_NAME +unsigned short fw12160i_version = 10*1024+1; +#else +unsigned short risc_code_version = 10*1024+1; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned char fw12160i_version_str[] = {10,1,19}; +#else +unsigned char firmware_version[] = {10,1,19}; +#endif + +#ifdef UNIQUE_FW_NAME +#define fw12160i_VERSION_STRING "10.1.19" +#else +#define FW_VERSION_STRING "10.1.19" +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw12160i_addr01 = 0x1000 ; +#else +unsigned short risc_code_addr01 = 0x1000 ; +#endif + +#ifdef UNIQUE_FW_NAME +unsigned short fw12160i_code01[] = { +#else +unsigned short risc_code01[] = { +#endif + 0x0804, 0x1041, 0x0000, 0x32f8, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, + 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, + 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, + 0x3132, 0x3136, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, + 0x6572, 0x7369, 0x6f6e, 0x2031, 0x302e, 0x3031, 0x2020, 0x2043, + 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, + 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, + 0x2400, 0x20c9, 0x8cff, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2001, + 0x01ff, 0x2004, 0xd0fc, 0x1120, 0x2071, 0x0100, 0x70a0, 0x70a2, + 0x20c1, 0x0020, 0x2089, 0x1223, 0x2071, 0x0010, 0x70c3, 0x0004, + 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x000a, + 0x2001, 0x04fd, 0x2004, 0x70d6, 0x2009, 0xfeff, 0x2130, 0x2128, + 0xa1a2, 0x4300, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, + 0xa192, 0x8d00, 0x2009, 0x0000, 0x2001, 0x0032, 0x080c, 0x1d83, + 0x2218, 0x2079, 0x4300, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, + 0x0040, 0x42a4, 0x8109, 0x1dd8, 0x2009, 0xff00, 0x3400, 0xa102, + 0x0218, 0x0110, 0x20a8, 0x42a4, 0x781b, 0x0064, 0x7814, 0xc0cd, + 0xc0d5, 0x7816, 0x2071, 0x0200, 0x00d6, 0x2069, 0x4340, 0x080c, + 0x42d8, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1130, 0x2069, 0x4380, + 0x2071, 0x0100, 0x080c, 0x42d8, 0x7814, 0xc0d4, 0x7816, 0x00de, + 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, 0xc08d, 0x7802, + 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, 0x7827, 0x0002, + 0x2009, 0x0002, 0x2069, 0x4340, 0x681b, 0x0003, 0x6823, 0x0007, + 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0000, + 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000, 0x8109, 0x0500, + 0x68d3, 0x000a, 0x68c3, 0x43c0, 0x2079, 0x4300, 0x68d7, 0x762d, + 0x68c7, 0x48c0, 0x68cb, 0x47c0, 0x68cf, 0x88c0, 0x68ab, 0x8b44, + 0x68af, 0x8b49, 0x68b3, 0x8b44, 0x68b7, 0x8b44, 0x68a7, 0x0001, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x11c8, 0x2069, 0x4380, 0x0860, + 0x68d3, 0x000a, 0x68c3, 0x45c0, 0x68d7, 0x7839, 0x68c7, 0x68c0, + 0x68cb, 0x4840, 0x68cf, 0x89d0, 0x68ab, 0x8b49, 0x68af, 0x8b4e, + 0x68b3, 0x8b49, 0x68b7, 0x8b49, 0x68a7, 0x0001, 0x00e6, 0x2069, + 0x47c0, 0x2071, 0x0200, 0x70ec, 0xd0e4, 0x2019, 0x1c09, 0x2021, + 0x0009, 0x1120, 0x2019, 0x1c0c, 0x2021, 0x000c, 0x080c, 0x1cf3, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1188, 0x2069, 0x4840, 0x2071, + 0x0100, 0x70ec, 0xd0e4, 0x2019, 0x1c09, 0x2021, 0x0009, 0x1120, + 0x2019, 0x1c0c, 0x2021, 0x000c, 0x080c, 0x1cf3, 0x00ee, 0x2011, + 0x0002, 0x2069, 0x48c0, 0x2009, 0x0002, 0x20a9, 0x0100, 0x6837, + 0x0000, 0x680b, 0x0040, 0x7bc8, 0xa386, 0xfeff, 0x1128, 0x6817, + 0x0100, 0x681f, 0x0064, 0x0020, 0x6817, 0x0064, 0x681f, 0x0002, + 0xade8, 0x0010, 0x1f04, 0x1137, 0x8109, 0x1d38, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x1128, 0x8211, 0x0118, 0x2069, 0x68c0, 0x08d8, + 0x080c, 0x2254, 0x080c, 0x3e39, 0x080c, 0x1b0f, 0x080c, 0x42a0, + 0x2091, 0x2200, 0x2079, 0x4300, 0x2071, 0x0050, 0x2091, 0x2400, + 0x2079, 0x4300, 0x2071, 0x0020, 0x2091, 0x2600, 0x2079, 0x0200, + 0x2071, 0x4340, 0x2091, 0x2800, 0x2079, 0x0100, 0x2071, 0x4380, + 0x2091, 0x2000, 0x2079, 0x4300, 0x2071, 0x0010, 0x3200, 0xa085, + 0x303d, 0x2090, 0x2071, 0x0010, 0x70c3, 0x0000, 0x1004, 0x118e, + 0x70c0, 0xa086, 0x0002, 0x1110, 0x080c, 0x13a3, 0x2039, 0x0000, + 0x080c, 0x129c, 0x78ac, 0xa005, 0x1180, 0x0e04, 0x119c, 0x786c, + 0xa065, 0x0110, 0x080c, 0x1ffe, 0x080c, 0x1da4, 0x0e04, 0x11b1, + 0x786c, 0xa065, 0x0110, 0x080c, 0x1ffe, 0x0e04, 0x11b1, 0x2009, + 0x4347, 0x2011, 0x4387, 0x2104, 0x220c, 0xa105, 0x0110, 0x080c, + 0x1c21, 0x2071, 0x4340, 0x70a4, 0xa005, 0x01e8, 0x7450, 0xa485, + 0x0000, 0x01c8, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4, 0xa28c, + 0x303d, 0x2190, 0x080c, 0x260d, 0x2091, 0x8000, 0x2091, 0x303d, + 0x0e04, 0x11d3, 0x2079, 0x4300, 0x786c, 0xa065, 0x0120, 0x2071, + 0x0010, 0x080c, 0x1ffe, 0x1d04, 0x11db, 0x2079, 0x4300, 0x2071, + 0x0010, 0x080c, 0x40ed, 0x2071, 0x4380, 0x70a4, 0xa005, 0x0188, + 0x7050, 0xa025, 0x0170, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d4, + 0xa28c, 0x303d, 0x2190, 0x080c, 0x260d, 0x2091, 0x8000, 0x2091, + 0x303d, 0x2079, 0x4300, 0x2071, 0x0010, 0x0e04, 0x11fc, 0x786c, + 0xa065, 0x0110, 0x080c, 0x1ffe, 0x1d04, 0x1190, 0x080c, 0x40ed, + 0x0804, 0x1190, 0x3c00, 0xa084, 0x0007, 0x0002, 0x120e, 0x120e, + 0x1210, 0x1210, 0x1215, 0x1215, 0x121a, 0x121a, 0x080c, 0x243b, + 0x2091, 0x2400, 0x080c, 0x3e9c, 0x0005, 0x2091, 0x2200, 0x080c, + 0x3e9c, 0x0005, 0x2091, 0x2200, 0x080c, 0x3e9c, 0x2091, 0x2400, + 0x080c, 0x3e9c, 0x0005, 0x1243, 0x1243, 0x1244, 0x1244, 0x124f, + 0x124f, 0x124f, 0x124f, 0x1258, 0x1258, 0x1263, 0x1263, 0x124f, + 0x124f, 0x124f, 0x124f, 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, + 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, 0x1272, + 0x1272, 0x1272, 0x1272, 0x0cf8, 0x0006, 0x0106, 0x0126, 0x2091, + 0x2800, 0x080c, 0x2458, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, + 0x0106, 0x0126, 0x080c, 0x1202, 0x012e, 0x010e, 0x000e, 0x000d, + 0x0006, 0x0106, 0x0126, 0x2091, 0x2600, 0x080c, 0x2458, 0x012e, + 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, 0x0126, 0x2091, 0x2600, + 0x080c, 0x2458, 0x2091, 0x2800, 0x080c, 0x2458, 0x012e, 0x010e, + 0x000e, 0x000d, 0x0006, 0x0106, 0x0126, 0x00e6, 0x00f6, 0x2079, + 0x4300, 0x2071, 0x0200, 0x2069, 0x4340, 0x3d00, 0xd08c, 0x1120, + 0x2069, 0x4380, 0x2071, 0x0100, 0x080c, 0x42d8, 0x00fe, 0x00ee, + 0x012e, 0x010e, 0x000e, 0x000d, 0x7008, 0x800b, 0x1240, 0x7007, + 0x0002, 0xa08c, 0x01e0, 0x1120, 0xd09c, 0x0108, 0x0887, 0x0897, + 0x70c3, 0x4002, 0x0804, 0x13a6, 0x0e04, 0x1308, 0x2061, 0x0000, + 0x6018, 0xd084, 0x1904, 0x1308, 0x7828, 0xa005, 0x1120, 0x0004, + 0x1309, 0x0804, 0x1308, 0xd0fc, 0x0148, 0x0006, 0x080c, 0x1aa9, + 0x000e, 0x0168, 0x2001, 0x4007, 0x0804, 0x13a5, 0x0006, 0x080c, + 0x1a9b, 0x000e, 0x0120, 0x2001, 0x4007, 0x0804, 0x13a5, 0x7910, + 0xd0fc, 0x1128, 0x2061, 0x4340, 0xc19c, 0xc7fc, 0x0020, 0x2061, + 0x4380, 0xc19d, 0xc7fd, 0x6064, 0xa005, 0x15d0, 0x7912, 0x6083, + 0x0000, 0x7828, 0xc0fc, 0xa086, 0x0018, 0x1120, 0x00c6, 0x080c, + 0x18c9, 0x00ce, 0x782b, 0x0000, 0x607c, 0xa065, 0x0190, 0x00c6, + 0x609c, 0x080c, 0x1b76, 0x00ce, 0x609f, 0x0000, 0x080c, 0x19db, + 0x2009, 0x0018, 0x6087, 0x0103, 0x080c, 0x1ab7, 0x1198, 0x080c, + 0x1b02, 0x7810, 0xd09c, 0x1118, 0x2061, 0x4340, 0x0020, 0x2061, + 0x4380, 0xc09c, 0x7812, 0x607f, 0x0000, 0x60d4, 0xd0c4, 0x0130, + 0xc0c4, 0x60d6, 0x2001, 0x4005, 0x0804, 0x13a5, 0x0804, 0x13a3, + 0x0005, 0xa006, 0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, + 0xa08a, 0x0040, 0x1a04, 0x1355, 0x0002, 0x13a3, 0x13f1, 0x13bf, + 0x1425, 0x1459, 0x1459, 0x13b7, 0x19f3, 0x1463, 0x13b1, 0x13c3, + 0x13c4, 0x13c5, 0x13c6, 0x19f7, 0x13b1, 0x1470, 0x14c5, 0x18e4, + 0x19ed, 0x13c7, 0x1795, 0x17cb, 0x17fa, 0x183d, 0x1752, 0x175f, + 0x1772, 0x1784, 0x159a, 0x13b1, 0x14f7, 0x1502, 0x1510, 0x151e, + 0x1535, 0x1543, 0x1546, 0x1554, 0x1562, 0x156c, 0x1580, 0x158c, + 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x15a7, 0x15b8, 0x15d2, 0x1606, + 0x162f, 0x1641, 0x1644, 0x1677, 0x16aa, 0x16bc, 0x1720, 0x1730, + 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x1742, 0x2100, 0xa08a, 0x0040, + 0x1a04, 0x13b1, 0x0002, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, + 0x1a19, 0x1a1f, 0x13b1, 0x13b1, 0x13b1, 0x1a23, 0x1a63, 0x13b1, + 0x13b1, 0x13b1, 0x13b1, 0x13ec, 0x1454, 0x146b, 0x14c0, 0x18df, + 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x1a67, 0x1a0b, 0x1a15, 0x13b1, + 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, + 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, + 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, + 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, 0x13b1, + 0x13b1, 0x13b1, 0x13b1, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0028, + 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0e04, 0x13a6, + 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, + 0x0005, 0x70c3, 0x4001, 0x0c90, 0x70c3, 0x4006, 0x0c78, 0x2099, + 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0c20, 0x70c4, + 0x70c3, 0x0004, 0x0807, 0x08f8, 0x08f0, 0x08e8, 0x08e0, 0x2091, + 0x8000, 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, + 0x2020, 0x70d3, 0x000a, 0x2001, 0x0001, 0x70d6, 0x2079, 0x0000, + 0x781b, 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, + 0x2051, 0x0445, 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, + 0x2091, 0x4080, 0x0804, 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, + 0x0018, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, + 0x20a0, 0x2099, 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, + 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, 0x0904, 0x13a3, + 0xa182, 0x0040, 0x1210, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, + 0x7007, 0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0de8, 0x7007, + 0x0002, 0xa084, 0x01e0, 0x0120, 0x70c3, 0x4002, 0x0804, 0x13a6, + 0x24a8, 0x53a5, 0x0c10, 0x0804, 0x13a3, 0x2029, 0x0000, 0x2520, + 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x2098, 0x20a1, 0x0030, 0x7003, + 0x0000, 0x7007, 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, + 0x0040, 0x7007, 0x0006, 0x81ff, 0x0904, 0x13a3, 0xa182, 0x0040, + 0x1210, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x24a8, 0x53a6, + 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0de8, 0xa084, 0x01e0, 0x0d48, + 0x70c3, 0x4002, 0x0804, 0x13a6, 0x75d8, 0x74dc, 0x75da, 0x74de, + 0x0878, 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x1108, 0x200a, + 0x72ca, 0x0804, 0x13a2, 0x70c7, 0x000a, 0x70cb, 0x0001, 0x70cf, + 0x0013, 0x0804, 0x13a3, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0018, + 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, + 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x05f0, 0xa40a, 0x0110, 0x1a04, + 0x13a5, 0x8001, 0x7872, 0xa084, 0xfc00, 0x0138, 0x78ac, 0xc085, + 0x78ae, 0x2001, 0x4005, 0x0804, 0x13a5, 0x7b7e, 0x7a7a, 0x7e86, + 0x7d82, 0x7c76, 0xa48c, 0xff00, 0x0170, 0x8407, 0x8004, 0x8004, + 0x810c, 0x810c, 0x810f, 0xa118, 0xa291, 0x0000, 0xa6b1, 0x0000, + 0xa581, 0x0000, 0x0050, 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, + 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, + 0x7026, 0xa605, 0x0118, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, + 0xfffc, 0x78ae, 0x0018, 0x78ac, 0xc085, 0x78ae, 0x0804, 0x13a3, + 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0018, 0x2029, 0x0000, 0x2530, + 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, + 0xa005, 0x0500, 0xa40a, 0x0110, 0x1a04, 0x13a5, 0x8001, 0x7892, + 0xa084, 0xfc00, 0x0138, 0x78ac, 0xc0c5, 0x78ae, 0x2001, 0x4005, + 0x0804, 0x13a5, 0x7a9a, 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, + 0x0118, 0x7a10, 0xc2c5, 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, + 0x78ae, 0x0018, 0x78ac, 0xc0c5, 0x78ae, 0x0804, 0x13a3, 0x2009, + 0x0000, 0x786c, 0xa065, 0x0118, 0x8108, 0x6000, 0x0cd8, 0x7ac4, + 0x0804, 0x13a1, 0x2009, 0x4348, 0x210c, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1904, 0x13a2, 0x2011, 0x4388, 0x2214, 0x0804, 0x13a1, + 0x2009, 0x4349, 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, + 0x13a2, 0x2011, 0x4389, 0x2214, 0x0804, 0x13a1, 0x2061, 0x4340, + 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1148, 0x2061, 0x4380, 0x6328, 0x73da, 0x632c, 0x831c, + 0x831c, 0x831c, 0x73de, 0x0804, 0x13a1, 0x2009, 0x434c, 0x210c, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13a2, 0x2011, 0x438c, + 0x2214, 0x0804, 0x13a1, 0x7918, 0x0804, 0x13a2, 0x2009, 0x434d, + 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13a2, 0x2011, + 0x438d, 0x2214, 0x0804, 0x13a1, 0x2009, 0x434e, 0x210c, 0x2001, + 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13a2, 0x2011, 0x438e, 0x2214, + 0x0804, 0x13a1, 0x7920, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, + 0x13a2, 0x7a24, 0x0804, 0x13a1, 0x2011, 0x4840, 0x71c4, 0xd1fc, + 0x1110, 0x2011, 0x47c0, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa268, 0x6a00, 0x6b08, 0x6c1c, 0x74da, 0x0804, 0x13a0, + 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, + 0x8001, 0x2708, 0x0804, 0x13a0, 0x2061, 0x4340, 0x6118, 0x2001, + 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13a2, 0x2061, 0x4380, 0x6218, + 0x0804, 0x13a1, 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6908, + 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0804, 0x13a0, 0x71c4, + 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x1a04, 0x139c, 0x080c, + 0x230e, 0xa384, 0x4000, 0x0110, 0xa295, 0x0020, 0x0804, 0x13a0, + 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, 0x1a04, 0x139c, 0xd1bc, + 0x1120, 0x2011, 0x4348, 0x2204, 0x0020, 0x2011, 0x4388, 0x2204, + 0xc0bd, 0x0006, 0x2100, 0xc0bc, 0x2012, 0x080c, 0x22b4, 0x001e, + 0x0804, 0x13a2, 0x71c4, 0x2021, 0x4349, 0x2404, 0x70c6, 0x2019, + 0x0000, 0x0030, 0x71c8, 0x2021, 0x4389, 0x2404, 0x70ca, 0xc3fd, + 0x2011, 0x15fe, 0x20a9, 0x0008, 0x2204, 0xa106, 0x0138, 0x8210, + 0x1f04, 0x15e4, 0x71c4, 0x72c8, 0x0804, 0x139b, 0xa292, 0x15fe, + 0x0026, 0x2122, 0x001e, 0x080c, 0x22c6, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1110, 0xd3fc, 0x09f0, 0x0804, 0x13a3, 0x03e8, 0x00fa, + 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x4340, + 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, + 0x8003, 0x8003, 0x8003, 0x602e, 0x2001, 0x01ff, 0x2004, 0xd0fc, + 0x11a0, 0x0026, 0x0016, 0x2061, 0x4380, 0x6128, 0x622c, 0x8214, + 0x8214, 0x8214, 0x70d8, 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, + 0x602e, 0x71da, 0x72de, 0x001e, 0x002e, 0x0804, 0x13a1, 0x2061, + 0x4340, 0x6130, 0x70c4, 0x6032, 0x2001, 0x01ff, 0x2004, 0xd0fc, + 0x1904, 0x13a2, 0x2061, 0x4380, 0x6230, 0x70c8, 0x6032, 0x0804, + 0x13a1, 0x7918, 0x0804, 0x13a2, 0x71c4, 0xa184, 0xffcf, 0x0148, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x139c, 0x72c8, 0x0804, + 0x139b, 0x2011, 0x434d, 0x2204, 0x2112, 0x0006, 0x2019, 0x0000, + 0x080c, 0x2302, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x0118, 0x001e, + 0x0804, 0x13a2, 0x71c8, 0xa184, 0xffcf, 0x0128, 0x0006, 0x2110, + 0x71c4, 0x0804, 0x139b, 0x2011, 0x438d, 0x2204, 0x2112, 0x0006, + 0xc3fd, 0x080c, 0x2302, 0x002e, 0x001e, 0x0804, 0x13a1, 0x71c4, + 0xa182, 0x0010, 0x0248, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, + 0x139c, 0x72c8, 0x0804, 0x139b, 0x2011, 0x434e, 0x2204, 0x0006, + 0x2112, 0x2019, 0x0000, 0x080c, 0x22ef, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x0118, 0x001e, 0x0804, 0x13a2, 0x71c8, 0xa182, 0x0010, + 0x0228, 0x0006, 0x2110, 0x71c4, 0x0804, 0x139b, 0x2011, 0x438e, + 0x2204, 0x0006, 0x2112, 0xc3fd, 0x080c, 0x22ef, 0x002e, 0x001e, + 0x0804, 0x13a1, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x1904, 0x139b, + 0xa284, 0xfffd, 0x1904, 0x139b, 0x2100, 0x7920, 0x7822, 0x2200, + 0x7a24, 0x7826, 0x0804, 0x13a1, 0x2011, 0x4840, 0x71c4, 0xd1fc, + 0x1110, 0x2011, 0x47c0, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa268, 0x72c8, 0x73cc, 0x74d8, 0x71c6, 0x6800, 0x70ca, + 0x73ce, 0x74da, 0x2091, 0x8000, 0x6a02, 0xd2ac, 0x1118, 0x2021, + 0x0000, 0x0078, 0xa484, 0x00ff, 0xa082, 0x0002, 0x16e8, 0x843f, + 0xa7bc, 0x00ff, 0x0130, 0xa786, 0x0002, 0x15b0, 0xa484, 0x00ff, + 0x0598, 0x2061, 0x0200, 0xd1fc, 0x0110, 0x2061, 0x0100, 0x2029, + 0x0009, 0x2031, 0x0062, 0x843f, 0xa7bc, 0x00ff, 0x0130, 0x8307, + 0xa084, 0x00ff, 0x1110, 0xa73d, 0x11f8, 0x2041, 0x001d, 0x8307, + 0xa084, 0x00ff, 0x0150, 0xa842, 0x02b8, 0xa3bc, 0x00ff, 0x2500, + 0xa702, 0x0290, 0x2600, 0xa702, 0x1278, 0x2039, 0x003a, 0x6804, + 0xa705, 0x6806, 0x6b0a, 0x6b0c, 0x73ce, 0x681c, 0x70da, 0x6c1e, + 0x2091, 0x8001, 0x0804, 0x13a3, 0x2091, 0x8001, 0x0804, 0x139d, + 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, + 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0804, 0x13a0, + 0x70c4, 0x2061, 0x4340, 0x6118, 0x601a, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1904, 0x13a2, 0x70c8, 0x2061, 0x4380, 0x6218, 0x601a, + 0x0804, 0x13a1, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x1a04, + 0x139c, 0x080c, 0x2332, 0xa384, 0x4000, 0x0110, 0xa295, 0x0020, + 0x0804, 0x13a0, 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6a08, + 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0804, 0x13a1, 0x77c4, + 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, + 0x6804, 0xa005, 0x0110, 0x080c, 0x2233, 0x2091, 0x8001, 0x2708, + 0x0804, 0x13a1, 0x77c4, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6a08, + 0xc295, 0x6a0a, 0x6804, 0xa005, 0x0110, 0x080c, 0x2233, 0x2091, + 0x8001, 0x2708, 0x0804, 0x13a1, 0x77c4, 0x2041, 0x0001, 0x2049, + 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x080c, 0x1b35, 0x2091, + 0x8001, 0x2708, 0x6a08, 0x0804, 0x13a1, 0x77c4, 0xd7fc, 0x0128, + 0x080c, 0x1aa9, 0x0138, 0x0804, 0x13a5, 0x080c, 0x1a9b, 0x0110, + 0x0804, 0x13a5, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, 0x080c, + 0x1bad, 0x11e8, 0x6818, 0xa005, 0x01a0, 0x2708, 0x0076, 0x080c, + 0x2351, 0x007e, 0x1170, 0x2001, 0x0015, 0xd7fc, 0x1118, 0x2061, + 0x4340, 0x0018, 0xc0fd, 0x2061, 0x4380, 0x782a, 0x2091, 0x8001, + 0x0005, 0x2091, 0x8001, 0x2001, 0x4005, 0x0804, 0x13a5, 0x2091, + 0x8001, 0x0804, 0x13a3, 0x77c4, 0xd7fc, 0x0128, 0x080c, 0x1aa9, + 0x0138, 0x0804, 0x13a5, 0x080c, 0x1a9b, 0x0110, 0x0804, 0x13a5, + 0x77c6, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, + 0x8000, 0x080c, 0x1b35, 0x2009, 0x0016, 0xd7fc, 0x1118, 0x2061, + 0x4340, 0x0018, 0x2061, 0x4380, 0xc1fd, 0x6067, 0x0003, 0x607f, + 0x0000, 0x6776, 0x6083, 0x000f, 0x792a, 0x080c, 0x2233, 0x2091, + 0x8001, 0x0005, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xd7fc, 0x0128, + 0x080c, 0x1aa9, 0x0138, 0x0804, 0x13a5, 0x080c, 0x1a9b, 0x0110, + 0x0804, 0x13a5, 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2009, 0x0017, + 0xd7fc, 0x1118, 0x2061, 0x4340, 0x0018, 0x2061, 0x4380, 0xc1fd, + 0x607f, 0x0000, 0x6067, 0x0002, 0x6776, 0x6083, 0x000f, 0x792a, + 0x080c, 0x2233, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, 0x0005, + 0x2051, 0x0010, 0x2091, 0x8000, 0x70c8, 0xa005, 0x0118, 0x60d4, + 0xc0fd, 0x60d6, 0x080c, 0x1b35, 0x70c8, 0x6836, 0x8738, 0xa784, + 0x001f, 0x1dc0, 0x2091, 0x8001, 0x0005, 0x72c8, 0xd284, 0x0128, + 0x080c, 0x1aa9, 0x0138, 0x0804, 0x13a5, 0x080c, 0x1a9b, 0x0110, + 0x0804, 0x13a5, 0x72c8, 0x72ca, 0x78ac, 0xa084, 0x0003, 0x1508, + 0x2039, 0x0000, 0xd284, 0x0108, 0xc7fd, 0x2041, 0x0021, 0x2049, + 0x0004, 0x2051, 0x0008, 0x080c, 0x1b1d, 0x2091, 0x8000, 0x6808, + 0xc0d4, 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, + 0x1d90, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, + 0x1d50, 0x2091, 0x8000, 0x72c8, 0x2069, 0x0100, 0xd284, 0x1110, + 0x2069, 0x0200, 0x6808, 0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, + 0x01b0, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, + 0x1f04, 0x1885, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, + 0x0110, 0x1f04, 0x188e, 0x20a9, 0x00fa, 0x1f04, 0x1895, 0x2079, + 0x4300, 0x2009, 0x0018, 0x72c8, 0xd284, 0x1118, 0x2061, 0x4340, + 0x0018, 0x2061, 0x4380, 0xc1fd, 0x792a, 0x6067, 0x0001, 0x6083, + 0x000f, 0x60a7, 0x0000, 0x60a8, 0x60b2, 0x60b6, 0x60d4, 0xd0b4, + 0x0160, 0xc0b4, 0x60d6, 0x00c6, 0x60b8, 0xa065, 0x6008, 0xc0d4, + 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x60d4, 0xa084, 0x7eff, + 0x60d6, 0x78ac, 0xc08d, 0x78ae, 0x681b, 0x0054, 0x2091, 0x8001, + 0x0005, 0xd7fc, 0x1118, 0x2069, 0x4340, 0x0010, 0x2069, 0x4380, + 0x71c4, 0x71c6, 0x6916, 0x81ff, 0x1110, 0x68a7, 0x0001, 0x78ac, + 0xc08c, 0x78ae, 0xd084, 0x1110, 0x080c, 0x1c00, 0x0005, 0x75d8, + 0x74dc, 0x75da, 0x74de, 0x0018, 0x2029, 0x0000, 0x2520, 0x71c4, + 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4300, 0x7dde, + 0x7cda, 0x7bd6, 0x7ad2, 0x080c, 0x1afa, 0x0904, 0x19d7, 0x20a9, + 0x0005, 0x20a1, 0x4314, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, + 0x2009, 0x0040, 0x080c, 0x1cbf, 0x0120, 0x080c, 0x1b02, 0x0804, + 0x19d7, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, 0x1120, 0x0006, + 0x080c, 0x1fe3, 0x000e, 0xa084, 0xff00, 0x8007, 0x8009, 0x0904, + 0x1981, 0x00c6, 0x2c68, 0x080c, 0x1afa, 0x05a8, 0x2c00, 0x689e, + 0x8109, 0x1dc0, 0x609f, 0x0000, 0x00ce, 0x00c6, 0x7ddc, 0x7cd8, + 0x7bd4, 0x7ad0, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, + 0xa5a9, 0x0000, 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x2c68, 0x689c, + 0xa065, 0x0904, 0x1980, 0x2009, 0x0040, 0x080c, 0x1cbf, 0x1550, + 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x1168, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x000a, 0x1120, 0x0016, 0x080c, 0x1fe0, 0x001e, + 0x2d00, 0x6002, 0x0898, 0x00ce, 0x00c6, 0x609c, 0x080c, 0x1b76, + 0x00ce, 0x609f, 0x0000, 0x080c, 0x19db, 0x2009, 0x0018, 0x6008, + 0xc0cd, 0x600a, 0x6004, 0x6086, 0x080c, 0x1ab7, 0x080c, 0x1b02, + 0x0804, 0x19d7, 0x00ce, 0x00c6, 0x609c, 0x080c, 0x1b76, 0x00ce, + 0x609f, 0x0000, 0x080c, 0x19db, 0x2009, 0x0018, 0x6087, 0x0103, + 0x601b, 0x0003, 0x080c, 0x1ab7, 0x080c, 0x1b02, 0x0804, 0x19d7, + 0x00ce, 0x6114, 0xd1fc, 0x0120, 0x080c, 0x1aa9, 0x01b8, 0x0018, + 0x080c, 0x1a9b, 0x0198, 0x2029, 0x0000, 0x2520, 0x2009, 0x0018, + 0x73c8, 0x72cc, 0x6087, 0x0103, 0x601b, 0x0021, 0x080c, 0x1ab7, + 0x080c, 0x1b02, 0x2001, 0x4007, 0x0804, 0x13a5, 0x74c4, 0x73c8, + 0x72cc, 0x6014, 0x2091, 0x8000, 0x00e6, 0x2009, 0x0012, 0xd0fc, + 0x1118, 0x2071, 0x4340, 0x0018, 0x2071, 0x4380, 0xc1fd, 0x792a, + 0x7067, 0x0005, 0x71d4, 0xa18c, 0xfe7f, 0x71d6, 0x736a, 0x726e, + 0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, 0x707e, 0xa02e, 0x2530, + 0x611c, 0xa184, 0x0060, 0x0110, 0x080c, 0x3de5, 0x00ee, 0x6596, + 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x6714, + 0x6023, 0x0000, 0x080c, 0x2233, 0x2091, 0x8001, 0x0005, 0x70c3, + 0x4005, 0x0804, 0x13a6, 0x20a9, 0x0005, 0x2099, 0x4314, 0x2091, + 0x8000, 0x530a, 0x2091, 0x8001, 0x2100, 0xa210, 0xa399, 0x0000, + 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0005, 0x71c4, 0x70c7, 0x0000, + 0x791e, 0x0804, 0x13a3, 0x71c4, 0x71c6, 0x2168, 0x0010, 0x2069, + 0x1000, 0x690c, 0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x1dd8, + 0xa285, 0x0000, 0x1118, 0x70c3, 0x4000, 0x0010, 0x70c3, 0x4003, + 0x70ca, 0x0804, 0x13a6, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, + 0x1a04, 0x139c, 0x7966, 0x0804, 0x13a3, 0x7964, 0x71c6, 0x0804, + 0x13a3, 0x7900, 0x71c6, 0x71c4, 0x7902, 0x0804, 0x13a3, 0x7900, + 0x71c6, 0x0804, 0x13a3, 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, + 0x0160, 0x810c, 0x0230, 0x8210, 0x810c, 0x810c, 0x0210, 0x8210, + 0x810c, 0x81ff, 0x1904, 0x139d, 0x8210, 0x7a0e, 0xd28c, 0x0538, + 0x7910, 0xc1cd, 0x7912, 0x2009, 0x0021, 0x2019, 0x0003, 0xd284, + 0x01c0, 0x8108, 0x2019, 0x0041, 0x2011, 0x8b4e, 0x2312, 0x2019, + 0x0042, 0x8210, 0x2312, 0x2019, 0x0043, 0x8210, 0x2312, 0x2019, + 0x0046, 0x8210, 0x2312, 0x2019, 0x0047, 0x8210, 0x2312, 0x2019, + 0x0006, 0x2011, 0x8b53, 0x2112, 0x2011, 0x8b73, 0x2312, 0x7904, + 0x7806, 0x0804, 0x13a2, 0x7804, 0x70c6, 0x0804, 0x13a3, 0x71c4, + 0xd1fc, 0x1118, 0x2011, 0x47c0, 0x0010, 0x2011, 0x4840, 0x8107, + 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x2011, 0x0000, + 0x6814, 0xd0fc, 0x0110, 0xa295, 0x0200, 0xd0b4, 0x0110, 0xa295, + 0x0001, 0x6b0c, 0x0804, 0x13a0, 0x0016, 0x7814, 0xd0f4, 0x0138, + 0x2001, 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0050, 0xd0fc, + 0x0138, 0x2001, 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0008, + 0xa006, 0x001e, 0x0005, 0x0016, 0x7814, 0xd0f4, 0x0138, 0x2001, + 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0008, 0xa006, 0x001e, + 0x0005, 0x0016, 0x7814, 0xd0fc, 0x0138, 0x2001, 0x4007, 0x70db, + 0x0001, 0xa18d, 0x0001, 0x0008, 0xa006, 0x001e, 0x0005, 0x7112, + 0x721a, 0x731e, 0x7810, 0xd0c4, 0x0110, 0x7422, 0x7526, 0xac80, + 0x0001, 0x8108, 0x810c, 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, + 0x0000, 0x6084, 0x20a2, 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, + 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, + 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, + 0xa006, 0xa211, 0x7d10, 0xd5c4, 0x0120, 0x7b84, 0xa319, 0x7c80, + 0xa421, 0x7008, 0xd0fc, 0x0de8, 0x7003, 0x0001, 0x7007, 0x0006, + 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0110, 0x7322, 0x7426, 0xa084, + 0x01e0, 0x0005, 0x7848, 0xa065, 0x0120, 0x2c04, 0x784a, 0x2063, + 0x0000, 0x0005, 0x00f6, 0x2079, 0x4300, 0x7848, 0x2062, 0x2c00, + 0xa005, 0x1110, 0x080c, 0x243b, 0x784a, 0x00fe, 0x0005, 0x2011, + 0x8d00, 0x7a4a, 0x7bc4, 0x8319, 0x0128, 0xa280, 0x0032, 0x2012, + 0x2010, 0x0cc8, 0x2013, 0x0000, 0x0005, 0x0016, 0x0026, 0xd7fc, + 0x1118, 0x2011, 0x48c0, 0x0010, 0x2011, 0x68c0, 0xa784, 0x0f00, + 0x800b, 0xa784, 0x001f, 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, + 0xa105, 0xa268, 0x002e, 0x001e, 0x0005, 0x0c39, 0x2900, 0x682a, + 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, 0xa80d, 0x690a, 0x00e6, + 0xd7fc, 0x1128, 0x2009, 0x4353, 0x2071, 0x4340, 0x0020, 0x2009, + 0x4393, 0x2071, 0x4380, 0x210c, 0x6804, 0xa005, 0x0148, 0xa116, + 0x1138, 0x2060, 0x6000, 0x6806, 0x0016, 0x200b, 0x0000, 0x0018, + 0x2009, 0x0000, 0x0016, 0x6804, 0xa065, 0x0178, 0x6000, 0x6806, + 0x0421, 0x080c, 0x1d30, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, + 0x6812, 0x1d88, 0x7910, 0xc1a5, 0x7912, 0x001e, 0x6902, 0x6906, + 0x2d00, 0x2060, 0x080c, 0x2580, 0x00ee, 0x0005, 0xa065, 0x0160, + 0x2008, 0x609c, 0xa005, 0x0128, 0x2062, 0x609f, 0x0000, 0xa065, + 0x0cc0, 0x7848, 0x794a, 0x2062, 0x0005, 0x6007, 0x0103, 0x608f, + 0x0000, 0x20a9, 0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, + 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022, 0x0005, 0x00e6, 0xd7fc, + 0x1128, 0x2071, 0x4340, 0x2031, 0x43c0, 0x0020, 0x2071, 0x4380, + 0x2031, 0x45c0, 0x7050, 0xa08c, 0x0200, 0x1128, 0xa608, 0x2d0a, + 0x8000, 0x7052, 0xa006, 0x00ee, 0x0005, 0x00f6, 0xd7fc, 0x1118, + 0x2079, 0x4340, 0x0010, 0x2079, 0x4380, 0x080c, 0x1b1d, 0x2091, + 0x8000, 0x6804, 0x780a, 0xa065, 0x0904, 0x1bfe, 0x0030, 0x2c00, + 0x780a, 0x2060, 0x6000, 0xa065, 0x05c8, 0x6010, 0xa306, 0x1db8, + 0x600c, 0xa206, 0x1da0, 0x2c28, 0x784c, 0xac06, 0x1108, 0x0458, + 0x6804, 0xac06, 0x1140, 0x6000, 0x2060, 0x6806, 0xa005, 0x1118, + 0x6803, 0x0000, 0x0048, 0x6400, 0x7808, 0x2060, 0x6402, 0xa486, + 0x0000, 0x1110, 0x2c00, 0x6802, 0x2560, 0x00fe, 0x080c, 0x1b85, + 0x00f6, 0x601b, 0x0005, 0x6023, 0x0020, 0x00fe, 0x080c, 0x1d30, + 0x00f6, 0x7908, 0x8109, 0x790a, 0x6810, 0x8001, 0x6812, 0x1118, + 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff, 0xa005, 0x00fe, 0x0005, + 0x0076, 0x2700, 0x2039, 0x0000, 0xd0fc, 0x0108, 0xc7fd, 0x2041, + 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x080c, + 0x1b35, 0x8738, 0xa784, 0x001f, 0x1dd0, 0xa7bc, 0xff00, 0x873f, + 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d90, 0x2091, 0x8001, 0x007e, + 0x0005, 0x786c, 0x2009, 0x8b74, 0x210c, 0xa10d, 0x0118, 0xa065, + 0x0804, 0x1ffe, 0x2061, 0x0000, 0x6018, 0xd084, 0x11b8, 0x7810, + 0xd08c, 0x0130, 0xc08c, 0x7812, 0xc7fc, 0x2069, 0x4340, 0x0028, + 0xc08d, 0x7812, 0x2069, 0x4380, 0xc7fd, 0x2091, 0x8000, 0x681c, + 0x681f, 0x0000, 0x2091, 0x8001, 0xa005, 0x1108, 0x0005, 0xa08c, + 0xfff0, 0x0110, 0x080c, 0x243b, 0x0002, 0x1c5d, 0x1c60, 0x1c66, + 0x1c6a, 0x1c5e, 0x1c6e, 0x1c5e, 0x1c5e, 0x1c5e, 0x1c73, 0x1c9f, + 0x1ca2, 0x1ca7, 0x1c5e, 0x1c5e, 0x1c5e, 0x0005, 0x080c, 0x243b, + 0x080c, 0x1c00, 0x2001, 0x8001, 0x0804, 0x1cb0, 0x2001, 0x8003, + 0x0804, 0x1cb0, 0x2001, 0x8004, 0x0804, 0x1cb0, 0x080c, 0x1c00, + 0x2001, 0x8006, 0x04e8, 0x2091, 0x8000, 0x0076, 0xd7fc, 0x1128, + 0x2069, 0x4340, 0x2039, 0x0009, 0x0020, 0x2069, 0x4380, 0x2039, + 0x0009, 0x6800, 0xa086, 0x0000, 0x0128, 0x000e, 0x6f1e, 0x2091, + 0x8001, 0x0005, 0x6874, 0x007e, 0xa0bc, 0xff00, 0x2041, 0x0021, + 0x2049, 0x0004, 0x2051, 0x0010, 0x080c, 0x1b35, 0x8738, 0xa784, + 0x001f, 0x1dd0, 0x2091, 0x8001, 0x2001, 0x800a, 0x0088, 0x2001, + 0x800c, 0x0070, 0x080c, 0x1c00, 0x2001, 0x800d, 0x0048, 0xd7fc, + 0x0110, 0x78ec, 0x0008, 0x78e4, 0x70c6, 0x2001, 0x800e, 0x0000, + 0x70c2, 0xd7fc, 0x1118, 0x70db, 0x0000, 0x0010, 0x70db, 0x0001, + 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x0005, 0xac80, + 0x0001, 0x81ff, 0x0518, 0x2099, 0x0030, 0x20a0, 0x700c, 0xa084, + 0x07ff, 0x0100, 0x7018, 0x0006, 0x701c, 0x0006, 0x7020, 0x0006, + 0x7024, 0x0006, 0x7112, 0x81ac, 0x721a, 0x731e, 0x7422, 0x7526, + 0x7003, 0x0001, 0x7007, 0x0001, 0x7008, 0x800b, 0x1ee8, 0x7007, + 0x0002, 0xa08c, 0x01e0, 0x1110, 0x53a5, 0xa006, 0x7003, 0x0000, + 0x7007, 0x0004, 0x000e, 0x7026, 0x000e, 0x7022, 0x000e, 0x701e, + 0x000e, 0x701a, 0x0005, 0x2011, 0x0020, 0x2009, 0x0010, 0x6b0a, + 0x6c0e, 0x681f, 0x0201, 0x6803, 0xfd20, 0x6807, 0x0038, 0x6a1a, + 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, 0x1d80, 0x0005, + 0x70ec, 0xd0dc, 0x1520, 0x2029, 0x0001, 0x7814, 0xd0cc, 0x1160, + 0x70ec, 0xd0e4, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1120, 0x2019, + 0x0c0c, 0x2021, 0x000c, 0x0070, 0x70ec, 0xd0e4, 0x1128, 0x2019, + 0x1c0c, 0x2021, 0x000c, 0x0030, 0x2019, 0x1c09, 0x2021, 0x0009, + 0xa5ad, 0x0200, 0x6b0a, 0x6c0e, 0x6d1e, 0x6807, 0x0038, 0x0005, + 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, 0x7868, 0xa005, 0x796a, + 0x0110, 0x2c02, 0x0008, 0x796e, 0x0005, 0x00c6, 0x2061, 0x4300, + 0x6887, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, + 0x0110, 0x2d02, 0x0008, 0x616e, 0x00ce, 0x0005, 0x2091, 0x8000, + 0x2c04, 0x786e, 0xa005, 0x1108, 0x786a, 0x2091, 0x8001, 0x609c, + 0xa005, 0x0188, 0x00c6, 0x2060, 0x2008, 0x609c, 0xa005, 0x0138, + 0x2062, 0x609f, 0x0000, 0xa065, 0x609c, 0xa005, 0x1dc8, 0x7848, + 0x794a, 0x2062, 0x00ce, 0x7848, 0x2062, 0x609f, 0x0000, 0xac85, + 0x0000, 0x1110, 0x080c, 0x243b, 0x784a, 0x0005, 0x20a9, 0x0010, + 0xa006, 0x8004, 0x8086, 0x818e, 0x1208, 0xa200, 0x1f04, 0x1d7a, + 0x8086, 0x818e, 0x0005, 0x0156, 0x20a9, 0x0010, 0xa005, 0x01b8, + 0xa11a, 0x12a8, 0x8213, 0x818d, 0x0228, 0xa11a, 0x1220, 0x1f04, + 0x1d8a, 0x0028, 0xa11a, 0x2308, 0x8210, 0x1f04, 0x1d8a, 0x0006, + 0x3200, 0xa084, 0xefff, 0x2080, 0x000e, 0x015e, 0x0005, 0x0006, + 0x3200, 0xa085, 0x1000, 0x0cb8, 0x7d74, 0x70d0, 0xa506, 0x0904, + 0x1e5b, 0x7810, 0x2050, 0x7800, 0xd08c, 0x0100, 0x080c, 0x1afa, + 0x0904, 0x1e5b, 0xa046, 0x7970, 0x2500, 0x8000, 0xa112, 0x2009, + 0x0040, 0x1208, 0x0030, 0x72d0, 0xa206, 0x0118, 0x8840, 0x2009, + 0x0080, 0x00c6, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, + 0x0020, 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0110, + 0x080c, 0x1afa, 0x7008, 0xd0fc, 0x0de8, 0x7007, 0x0002, 0x2091, + 0x8001, 0xa08c, 0x01e0, 0x1538, 0x53a5, 0x8cff, 0x1120, 0x88ff, + 0x0904, 0x1e48, 0x0050, 0x2c00, 0x788e, 0x20a9, 0x0020, 0xac80, + 0x0001, 0x20a0, 0x53a5, 0x0804, 0x1e48, 0xa046, 0x7218, 0x731c, + 0xdac4, 0x0110, 0x7420, 0x7524, 0xa292, 0x0040, 0xa39b, 0x0000, + 0xa4a3, 0x0000, 0xa5ab, 0x0000, 0x721a, 0x731e, 0xdac4, 0x0118, + 0x7422, 0x7526, 0xa006, 0x7007, 0x0004, 0x0904, 0x1e48, 0x8cff, + 0x0110, 0x080c, 0x1b02, 0x00ce, 0x080c, 0x1b02, 0xa046, 0x7888, + 0x8000, 0x788a, 0xa086, 0x0002, 0x01c0, 0x7a7c, 0x7b78, 0xdac4, + 0x0110, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, 0xa210, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, 0x731e, + 0xdac4, 0x0588, 0x7422, 0x7526, 0x0470, 0x6014, 0xd0fc, 0x1118, + 0x2069, 0x4340, 0x0010, 0x2069, 0x4380, 0x2091, 0x8000, 0x681f, + 0x0002, 0x88ff, 0x0120, 0xa046, 0x788c, 0x2060, 0x0c70, 0x788b, + 0x0000, 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0098, + 0x00ce, 0x788b, 0x0000, 0x080c, 0x1fb9, 0x6004, 0xa084, 0x000f, + 0x0059, 0x88ff, 0x0130, 0x788c, 0x2060, 0x6004, 0xa084, 0x000f, + 0x0019, 0x0804, 0x1da4, 0x0005, 0x0002, 0x1e6d, 0x1e88, 0x1ea1, + 0x1e6d, 0x1eae, 0x1e7e, 0x1e6d, 0x1e6d, 0x1e6d, 0x1e86, 0x1e9f, + 0x1e6d, 0x1e6d, 0x1e6d, 0x1e6d, 0x1e6d, 0x2039, 0x0400, 0x78bc, + 0xa705, 0x78be, 0x6008, 0xa705, 0x600a, 0x080c, 0x1eea, 0x609c, + 0x78ba, 0x609f, 0x0000, 0x080c, 0x1fa5, 0x0005, 0x78bc, 0xd0c4, + 0x0108, 0x0c58, 0x601c, 0xc0bd, 0x601e, 0x0030, 0x080c, 0x1fe3, + 0x78bc, 0xd0c4, 0x0108, 0x0c08, 0x78bf, 0x0000, 0x6004, 0x8007, + 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0138, 0x080c, 0x1eea, 0x0120, + 0x78bc, 0xc0c5, 0x78be, 0x0010, 0x0804, 0x1f05, 0x0005, 0x080c, + 0x1fe0, 0x78bc, 0xa08c, 0x0e00, 0x1110, 0xd0c4, 0x1108, 0x0828, + 0x080c, 0x1eea, 0x1110, 0x0804, 0x1f05, 0x0005, 0x78bc, 0xd0c4, + 0x0110, 0x0804, 0x1e6d, 0x78bf, 0x0000, 0x6714, 0x2011, 0x0001, + 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0188, 0xa7bc, 0xff00, + 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0150, 0xa7bc, 0x8000, 0x2011, + 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0108, 0x00c0, 0x080c, + 0x1b1d, 0x2d00, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, + 0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, 0x8001, + 0x1f04, 0x1ed2, 0x8211, 0x0118, 0x20a9, 0x0100, 0x0c58, 0x080c, + 0x1b02, 0x0005, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, + 0x1110, 0x78ba, 0x0038, 0x689e, 0x2d00, 0x6002, 0x78b8, 0xad06, + 0x1108, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x1130, 0x78bc, 0xc0c4, + 0x78be, 0x78b8, 0x2060, 0xa006, 0x0005, 0x00e6, 0xa02e, 0x2530, + 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2, 0x2048, 0xa984, + 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0110, 0x080c, 0x3de5, 0x6596, + 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, 0x4380, 0xd7fc, 0x1110, + 0x2071, 0x4340, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x0120, + 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, + 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, + 0x60c2, 0x2091, 0x8000, 0x6e08, 0xd684, 0x0170, 0xd9fc, 0x1160, + 0x2091, 0x8001, 0x080c, 0x1b85, 0x2091, 0x8000, 0x080c, 0x1d30, + 0x2091, 0x8001, 0x0804, 0x1fa3, 0x6024, 0xa096, 0x0001, 0x1110, + 0x8000, 0x6026, 0x6a10, 0x6814, 0xa202, 0x0268, 0x0160, 0x2091, + 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, 0x080c, + 0x1fa5, 0x0804, 0x1fa3, 0x2c08, 0xd9fc, 0x01f0, 0x6800, 0xa065, + 0x01d8, 0x6a04, 0x7000, 0xa084, 0x0002, 0x0168, 0x704c, 0xa206, + 0x1150, 0x6b04, 0x2160, 0x2304, 0x6002, 0xa005, 0x1108, 0x6902, + 0x2260, 0x6102, 0x0098, 0x2d00, 0x2060, 0x080c, 0x2580, 0x6e08, + 0x2160, 0x6202, 0x6906, 0x0050, 0x6800, 0x6902, 0xa065, 0x0110, + 0x6102, 0x0008, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160, 0xd9fc, + 0x0118, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, 0x7d08, 0x8528, 0x7d0a, + 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, 0x0128, 0xa6b6, 0x0040, + 0x6e0a, 0x080c, 0x1b96, 0x00ee, 0x0005, 0x6008, 0xa705, 0x600a, + 0x2091, 0x8000, 0x080c, 0x1d30, 0x2091, 0x8001, 0x78b8, 0xa065, + 0x0128, 0x609c, 0x78ba, 0x609f, 0x0000, 0x0c78, 0x78b6, 0x78ba, + 0x0005, 0x7970, 0x7874, 0x2818, 0xd384, 0x0118, 0x8000, 0xa112, + 0x0220, 0x8000, 0xa112, 0x1278, 0xc384, 0x7a7c, 0x721a, 0x7a78, + 0x721e, 0xdac4, 0x0120, 0x7a84, 0x7222, 0x7a80, 0x7226, 0xa006, + 0xd384, 0x0108, 0x8000, 0x7876, 0x70d2, 0x781c, 0xa005, 0x0138, + 0x8001, 0x781e, 0x1120, 0x0e04, 0x1fdf, 0x2091, 0x4080, 0x0005, + 0x2039, 0x1ff5, 0x0010, 0x2039, 0x1ffb, 0x2704, 0xa005, 0x0160, + 0xac00, 0x2068, 0x6908, 0x6810, 0x6912, 0x680a, 0x690c, 0x6814, + 0x6916, 0x680e, 0x8738, 0x0c88, 0x0005, 0x0003, 0x0009, 0x000f, + 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x2041, 0x0000, + 0x780c, 0x0002, 0x21a7, 0x2182, 0x2006, 0x2076, 0x2039, 0x8b74, + 0x2734, 0x7d10, 0x00c0, 0x6084, 0xa086, 0x0103, 0x1904, 0x2060, + 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, 0x11d8, 0x0804, 0x2060, + 0x8603, 0xa080, 0x8b55, 0x620c, 0x2202, 0x8000, 0x6210, 0x2202, + 0x080c, 0x1d4e, 0x8630, 0xa68e, 0x000f, 0x0904, 0x20e1, 0x786c, + 0xa065, 0x1d08, 0x7808, 0xa602, 0x1220, 0xd5ac, 0x1110, 0x263a, + 0x0005, 0xa682, 0x0003, 0x1a04, 0x20e1, 0x2091, 0x8000, 0x2069, + 0x0000, 0x6818, 0xd084, 0x11f8, 0x2011, 0x8b55, 0x2204, 0x70c6, + 0x8210, 0x2204, 0x70ca, 0xd684, 0x1130, 0x8210, 0x2204, 0x70da, + 0x8210, 0x2204, 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, 0x0001, + 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, + 0x203b, 0x0000, 0x0005, 0x7810, 0xc0ad, 0x7812, 0x0804, 0x20e1, + 0x263a, 0x080c, 0x21ad, 0x1904, 0x21c9, 0x786c, 0xa065, 0x1904, + 0x200b, 0x2091, 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0108, + 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0804, 0x21c9, 0x2039, 0x8b74, + 0x2734, 0x7d10, 0x00a0, 0x6084, 0xa086, 0x0103, 0x1904, 0x20cb, + 0x6114, 0x6018, 0xa105, 0x0120, 0x86ff, 0x11b8, 0x0804, 0x20cb, + 0xa680, 0x8b55, 0x620c, 0x2202, 0x080c, 0x1d4e, 0x8630, 0xa68e, + 0x001e, 0x0904, 0x20e1, 0x786c, 0xa065, 0x1d28, 0x7808, 0xa602, + 0x1220, 0xd5ac, 0x1110, 0x263a, 0x0005, 0xa682, 0x0006, 0x1a04, + 0x20e1, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x11f8, + 0x2011, 0x8b55, 0x2009, 0x8b4e, 0x26a8, 0x211c, 0x2204, 0x201a, + 0x8108, 0x8210, 0x1f04, 0x20ad, 0xa685, 0x8030, 0x70c2, 0x681b, + 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, + 0x8001, 0xa006, 0x2009, 0x8b75, 0x200a, 0x203a, 0x0005, 0x7810, + 0xc0ad, 0x7812, 0x00b0, 0x263a, 0x080c, 0x21ad, 0x1904, 0x21c9, + 0x786c, 0xa065, 0x1904, 0x207b, 0x2091, 0x8000, 0x7810, 0xa084, + 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0804, + 0x21c9, 0x2091, 0x8000, 0x7007, 0x0004, 0x7994, 0x70d4, 0xa102, + 0x0228, 0x0168, 0x7b90, 0xa302, 0x1150, 0x0010, 0x8002, 0x1138, + 0x263a, 0x7810, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0005, 0xa184, + 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, + 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, 0x7a9c, 0xa210, 0x721a, + 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, 0x0130, 0x7aa4, 0xa211, + 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, 0x0030, 0x7003, 0x0000, + 0x2009, 0x8b54, 0x260a, 0x8109, 0x2198, 0x2104, 0xd084, 0x0108, + 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6, 0x8603, 0x7012, 0x7007, + 0x0001, 0x7990, 0x7894, 0x8000, 0xa10a, 0x1208, 0xa006, 0x2028, + 0x7974, 0xa184, 0xff00, 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, + 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, 0x8004, 0x8004, 0x797c, + 0xa108, 0x7a78, 0xa006, 0xa211, 0xd4c4, 0x0120, 0x7b84, 0xa319, + 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0de8, 0xa084, 0x01e0, 0x01d0, + 0x7d10, 0x2031, 0x8b54, 0x2634, 0x78a8, 0x8000, 0x78aa, 0xd08c, + 0x1138, 0x7007, 0x0006, 0x7004, 0xd094, 0x1de8, 0x0804, 0x20e3, + 0x2069, 0x4347, 0x206b, 0x0003, 0x78ac, 0xa085, 0x0300, 0x78ae, + 0xa006, 0x0048, 0x2030, 0x75d6, 0x2091, 0x4080, 0x7d96, 0x7d10, + 0xa5ac, 0xffcf, 0x7d12, 0x2091, 0x8001, 0x78aa, 0x7007, 0x0006, + 0x263a, 0x7003, 0x0001, 0x711a, 0x721e, 0xd5c4, 0x0110, 0x7322, + 0x7426, 0x0005, 0x6084, 0xa086, 0x0103, 0x11d8, 0x6114, 0x6018, + 0xa105, 0x11b8, 0x2069, 0x0000, 0x6818, 0xd084, 0x1190, 0x600c, + 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, 0x2091, + 0x4080, 0x080c, 0x1d4e, 0x0e04, 0x21a0, 0x786c, 0xa065, 0x1d10, + 0x0005, 0x0059, 0x1530, 0x786c, 0xa065, 0x19e0, 0x0410, 0x0029, + 0x1500, 0x786c, 0xa065, 0x1dd8, 0x00e0, 0x6084, 0xa086, 0x0103, + 0x1168, 0x6018, 0xc0fc, 0x601a, 0xa086, 0x0004, 0x1138, 0x7804, + 0xd0a4, 0x0120, 0x080c, 0x1d4e, 0xa006, 0x0005, 0x0079, 0x1118, + 0xa085, 0x0001, 0x0005, 0x00b9, 0x1110, 0x2041, 0x0001, 0x7d10, + 0x0005, 0x88ff, 0x0110, 0x2091, 0x4080, 0x0005, 0x7b90, 0x7994, + 0x70d4, 0xa102, 0x1118, 0xa385, 0x0000, 0x0005, 0x0210, 0xa302, + 0x0005, 0x8002, 0x0005, 0xa184, 0xff00, 0x0140, 0x810f, 0x810c, + 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, 0x8004, + 0x8004, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa210, 0xa006, 0xa319, + 0xa421, 0xa529, 0x2009, 0x0018, 0x6028, 0xa005, 0x0110, 0x2009, + 0x0040, 0x080c, 0x1ab7, 0x01d0, 0x78a8, 0x8000, 0x78aa, 0xd08c, + 0x1510, 0x6014, 0xd0fc, 0x1118, 0x2069, 0x4340, 0x0010, 0x2069, + 0x4380, 0x2091, 0x8000, 0x681f, 0x0003, 0x78ab, 0x0000, 0x78ac, + 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, 0x0068, 0x78ab, 0x0000, + 0x080c, 0x1d4e, 0x7990, 0x7894, 0x8000, 0xa10a, 0x1208, 0xa006, + 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, 0x0005, + 0x2138, 0xd7fc, 0x1118, 0x2009, 0x4359, 0x0010, 0x2009, 0x4399, + 0x2091, 0x8000, 0x200a, 0x00f6, 0x2009, 0x4380, 0x2079, 0x0100, + 0xd7fc, 0x1120, 0x2009, 0x4340, 0x2079, 0x0200, 0x2104, 0xa086, + 0x0000, 0x1180, 0xd7fc, 0x1118, 0x2009, 0x4345, 0x0010, 0x2009, + 0x4385, 0x2104, 0xa005, 0x1130, 0x7830, 0xa084, 0x00c0, 0x1110, + 0x781b, 0x0052, 0x00fe, 0x0005, 0x2009, 0x0002, 0x2069, 0x4300, + 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x22a9, 0x2071, 0x4380, + 0x2079, 0x0100, 0x2021, 0x45bf, 0x784b, 0x000f, 0x2001, 0x01ff, + 0x2004, 0xd0fc, 0x0118, 0x2019, 0x3c3b, 0x0030, 0x20a1, 0x012b, + 0x2019, 0x3c3b, 0xd184, 0x0110, 0x20a1, 0x022b, 0x2304, 0xa005, + 0x0140, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, + 0x0ca8, 0x789b, 0x0000, 0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, + 0x0000, 0x78af, 0x2020, 0x1f04, 0x2287, 0x7003, 0x0000, 0x0016, + 0xd18c, 0x2009, 0x0000, 0x0108, 0xc1bd, 0x080c, 0x23bd, 0x001e, + 0x7020, 0xa084, 0x000f, 0xa085, 0x6300, 0x7806, 0x780f, 0x9000, + 0x7843, 0x00d8, 0x7853, 0x0090, 0x780b, 0x0308, 0x7456, 0x7053, + 0x0000, 0x8109, 0x0140, 0x2071, 0x4340, 0x2079, 0x0200, 0x2021, + 0x43bf, 0x0804, 0x2264, 0x0005, 0x0016, 0x2011, 0x0101, 0xd1bc, + 0x1110, 0x2011, 0x0201, 0xa18c, 0x000f, 0x2204, 0xa084, 0xfff0, + 0xa105, 0x2012, 0x001e, 0x080c, 0x23bd, 0x0005, 0x2011, 0x0101, + 0xd3fc, 0x1110, 0x2011, 0x0201, 0x20a9, 0x0009, 0x810b, 0x1f04, + 0x22ce, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, + 0x0005, 0x2019, 0x0002, 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, + 0x1f04, 0x22df, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, + 0x200a, 0x8319, 0x0118, 0x2009, 0x0201, 0x0c78, 0x0005, 0x2011, + 0x0101, 0xd3fc, 0x1110, 0x2011, 0x0201, 0x20a9, 0x000c, 0x810b, + 0x1f04, 0x22f7, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, + 0x2012, 0x0005, 0x2011, 0x0102, 0xd3fc, 0x1110, 0x2011, 0x0202, + 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x0005, 0x00c6, 0x2061, + 0x0100, 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, + 0xa080, 0x0020, 0x609a, 0x62ac, 0x63ac, 0x00ce, 0x0005, 0x00c6, + 0x2061, 0x0100, 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, + 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, + 0x00ce, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc, 0x1110, 0x2061, + 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, + 0xa28c, 0x0020, 0x0118, 0xc2ac, 0xa39d, 0x4000, 0xc3ec, 0xd3b4, + 0x1108, 0xc3ed, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x00ce, + 0x0005, 0x2091, 0x8000, 0x00c6, 0x00e6, 0x6818, 0xa005, 0x0904, + 0x23a1, 0xd1fc, 0x0118, 0x2061, 0x8ad0, 0x0010, 0x2061, 0x89c0, + 0x080c, 0x23a9, 0x0538, 0x20a9, 0x0101, 0xd1fc, 0x0118, 0x2061, + 0x89d0, 0x0010, 0x2061, 0x88c0, 0x00c6, 0x04d9, 0x0128, 0x00ce, + 0x8c60, 0x1f04, 0x236c, 0x0468, 0x000e, 0xd1fc, 0x0128, 0xa082, + 0x89d0, 0x2071, 0x4380, 0x0020, 0xa082, 0x88c0, 0x2071, 0x4340, + 0x707a, 0x7176, 0x2001, 0x0004, 0x7066, 0x7083, 0x000f, 0x080c, + 0x2228, 0x00a0, 0xd1fc, 0x1118, 0x2071, 0x4340, 0x0010, 0x2071, + 0x4380, 0x6020, 0xc0dd, 0x6022, 0x7176, 0x2c00, 0x707e, 0x2001, + 0x0006, 0x7066, 0x7083, 0x000f, 0x080c, 0x2228, 0x2001, 0x0000, + 0x0010, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x00ee, 0x00ce, + 0x0005, 0x2c04, 0xa005, 0x0170, 0x2060, 0x6010, 0xa306, 0x1140, + 0x600c, 0xa206, 0x1128, 0x6014, 0xa106, 0x1110, 0xa006, 0x0020, + 0x6000, 0x0c80, 0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6, 0x0016, + 0x2079, 0x4380, 0x2071, 0x0100, 0xd1bc, 0x1120, 0x2079, 0x4340, + 0x2071, 0x0200, 0x7920, 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x1110, + 0x001e, 0x0060, 0x810b, 0x810b, 0x810b, 0x810b, 0x000e, 0xa18d, + 0x0800, 0xd0bc, 0x1110, 0xa18d, 0x0f00, 0x2104, 0x00ee, 0x00fe, + 0x0005, 0x00e6, 0x2001, 0x4301, 0x2004, 0xd0ac, 0x1904, 0x2439, + 0x68e4, 0xd0ac, 0x0904, 0x2439, 0xa084, 0x0006, 0x1904, 0x2439, + 0x6014, 0xd0fc, 0x1118, 0x2071, 0x47c0, 0x0010, 0x2071, 0x4840, + 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, + 0xa084, 0x000a, 0x15b0, 0x7108, 0xa194, 0xff00, 0x0590, 0xa18c, + 0x00ff, 0x2001, 0x000a, 0xa106, 0x01a8, 0x2001, 0x000c, 0xa106, + 0x01a0, 0x2001, 0x0012, 0xa106, 0x0198, 0x2001, 0x0014, 0xa106, + 0x0190, 0x2001, 0x0019, 0xa106, 0x0188, 0x2001, 0x0032, 0xa106, + 0x0180, 0x0090, 0x2009, 0x000c, 0x0088, 0x2009, 0x0012, 0x0070, + 0x2009, 0x0014, 0x0058, 0x2009, 0x0019, 0x0040, 0x2009, 0x0020, + 0x0028, 0x2009, 0x003f, 0x0010, 0x2011, 0x0000, 0x2100, 0xa205, + 0x700a, 0x00ee, 0x0005, 0x0e04, 0x243b, 0x2091, 0x8000, 0x2071, + 0x0000, 0x0006, 0x7018, 0xd084, 0x1de8, 0x000e, 0x2071, 0x0010, + 0x70ca, 0x000e, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x0a01, 0x70df, + 0x0013, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0cf8, + 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708e, 0x7592, 0x7496, + 0x769a, 0x779e, 0xa594, 0x003f, 0xd4f4, 0x0138, 0xd7bc, 0x1128, + 0xa784, 0x007d, 0x1904, 0x3ace, 0x0871, 0xa49c, 0x000f, 0xa382, + 0x0004, 0x0320, 0xa3a6, 0x0007, 0x1930, 0x2418, 0x8507, 0xa084, + 0x000f, 0x0002, 0x2a4f, 0x2b10, 0x2b38, 0x2d71, 0x30cc, 0x3112, + 0x31a7, 0x3220, 0x32db, 0x33a6, 0x248d, 0x248a, 0x285b, 0x295c, + 0x30a0, 0x248a, 0x080c, 0x243b, 0x0005, 0xa006, 0x0038, 0x7808, + 0xc08d, 0x780a, 0xa006, 0x7002, 0x704e, 0x7046, 0x70d2, 0x7060, + 0xa005, 0x1904, 0x25d9, 0x7064, 0xa084, 0x0007, 0x0002, 0x24a7, + 0x2513, 0x251b, 0x2524, 0x252d, 0x25bf, 0x2536, 0x2513, 0x7830, + 0xd0bc, 0x1d10, 0x71d4, 0xd1b4, 0x1904, 0x24f0, 0x70a4, 0xa086, + 0x0001, 0x09d0, 0x70b4, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, + 0x0080, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, + 0xa05d, 0xa886, 0x0001, 0x0118, 0x69bc, 0x7daa, 0x79aa, 0x68c0, + 0xa04d, 0x6e1c, 0x2001, 0x0010, 0x0804, 0x270a, 0x7060, 0xa005, + 0x1904, 0x248c, 0x00c6, 0x00d6, 0x70b4, 0xa06d, 0x6800, 0xa065, + 0xa055, 0x789b, 0x0080, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, + 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0118, 0x69bc, 0x7daa, + 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0020, 0x0804, 0x270a, + 0x080c, 0x3a8d, 0x1904, 0x248c, 0x781b, 0x0068, 0x70bc, 0xa06d, + 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, + 0x7808, 0xc08d, 0x780a, 0x68bc, 0x7042, 0xc1b4, 0x71d6, 0x70b8, + 0xa065, 0x68c0, 0x705a, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, + 0x0009, 0x7046, 0x0005, 0x080c, 0x3a8d, 0x1120, 0x781b, 0x0054, + 0x7003, 0x0004, 0x0005, 0x080c, 0x3a8d, 0x1128, 0x2011, 0x000c, + 0x0419, 0x7003, 0x0004, 0x0005, 0x080c, 0x3a8d, 0x1128, 0x2011, + 0x0006, 0x00d1, 0x7003, 0x0004, 0x0005, 0x080c, 0x3a8d, 0x1128, + 0x2011, 0x000d, 0x0089, 0x7003, 0x0004, 0x0005, 0x080c, 0x3a8d, + 0x1150, 0x2011, 0x0006, 0x0041, 0x707c, 0x707f, 0x0000, 0x2068, + 0x704e, 0x7003, 0x0001, 0x0005, 0x7174, 0xc1fc, 0x8107, 0x7882, + 0x789b, 0x0080, 0xa286, 0x000c, 0x1120, 0x7aaa, 0x2001, 0x0001, + 0x0098, 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286, 0x000d, + 0x0120, 0x7aaa, 0x2001, 0x0002, 0x0038, 0x78ab, 0x0020, 0x7178, + 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b, 0x0060, 0x78aa, 0x785b, + 0x0004, 0x781b, 0x0113, 0x080c, 0x3aa0, 0x7083, 0x000f, 0x70d4, + 0xd0b4, 0x0168, 0xc0b4, 0x70d6, 0x00c6, 0x70b8, 0xa065, 0x6008, + 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x0005, + 0x7014, 0xa005, 0x1138, 0x70d4, 0xd0b4, 0x0128, 0x70b8, 0xac06, + 0x1110, 0x0c29, 0x0005, 0x0016, 0x71a4, 0xa186, 0x0001, 0x0528, + 0x00d6, 0x0026, 0x2100, 0x2011, 0x0001, 0xa212, 0x70b4, 0x2068, + 0x6800, 0xac06, 0x0120, 0x8211, 0x01b0, 0x00c9, 0x0cc8, 0x00c6, + 0x2100, 0x2011, 0x0001, 0xa212, 0x70b4, 0x2068, 0x6800, 0x2060, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x8211, 0x0110, 0x0041, 0x0cb0, + 0x70a7, 0x0001, 0x00ce, 0x002e, 0x00de, 0x001e, 0x0005, 0xade8, + 0x0005, 0x70ac, 0xad06, 0x1110, 0x70a8, 0x2068, 0x0005, 0x080c, + 0x3a8d, 0x1904, 0x248c, 0x707c, 0x2068, 0x7774, 0x080c, 0x396d, + 0x2c50, 0x080c, 0x3b28, 0x789b, 0x0080, 0x6814, 0xa084, 0x001f, + 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, 0x2001, 0x0004, 0x0804, + 0x270f, 0x080c, 0x3a8d, 0x1904, 0x248c, 0x789b, 0x0080, 0x7060, + 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0168, 0xc0b4, 0x70d6, 0x00c6, + 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, + 0x601a, 0x00ce, 0x080c, 0x396d, 0x2c50, 0x080c, 0x3b28, 0x6824, + 0xa005, 0x0130, 0xa082, 0x0006, 0x0208, 0x0010, 0x6827, 0x0005, + 0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, + 0x0001, 0x2001, 0x0003, 0x0804, 0x270f, 0xc28d, 0x72d6, 0x72c0, + 0xa200, 0xa015, 0x7154, 0x8108, 0xa12a, 0x0208, 0x71c0, 0x2164, + 0x6504, 0x85ff, 0x1170, 0x7156, 0x8421, 0x1da8, 0x70d4, 0xd08c, + 0x0128, 0x70d0, 0xa005, 0x1110, 0x70d3, 0x000a, 0x0005, 0x2200, + 0x0c90, 0x70d4, 0xc08c, 0x70d6, 0x70d3, 0x0000, 0x6034, 0xa005, + 0x1db0, 0x6708, 0xa784, 0x073f, 0x01d0, 0xd7d4, 0x1d80, 0xa784, + 0x0021, 0x1d68, 0xa784, 0x0002, 0x0130, 0xa784, 0x0004, 0x0d38, + 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, 0x1d08, 0xa784, 0x0100, + 0x0130, 0x6018, 0xa005, 0x19d8, 0xa7bc, 0xfeff, 0x670a, 0x2568, + 0x6823, 0x0000, 0x6e1c, 0xa684, 0x000e, 0x6318, 0x0128, 0x601c, + 0xa302, 0x0220, 0x0118, 0x0858, 0x83ff, 0x1948, 0x2d58, 0x2c50, + 0x7156, 0xd7bc, 0x1110, 0x7028, 0x6022, 0xc7bc, 0x670a, 0x68c0, + 0xa065, 0xa04d, 0x6100, 0x2a60, 0x2041, 0x0001, 0x6b14, 0xa39c, + 0x001f, 0xa39d, 0x00c0, 0xd1fc, 0x0110, 0xd684, 0x0110, 0xa39c, + 0xffbf, 0xd6a4, 0x0110, 0xa39d, 0x0020, 0xa684, 0x000e, 0x1904, + 0x26c1, 0xc7a5, 0x670a, 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, + 0x1178, 0x70d4, 0xd0b4, 0x1160, 0x7000, 0xa082, 0x0002, 0x1240, + 0x7830, 0xd0bc, 0x1128, 0x789b, 0x0080, 0x7baa, 0x0804, 0x2708, + 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, 0x0005, 0x70ac, 0xa606, + 0x1108, 0x76a8, 0x76b2, 0x2c3a, 0x8738, 0x2d3a, 0x8738, 0x283a, + 0x8738, 0x233a, 0x8738, 0x253a, 0x7830, 0xd0bc, 0x0150, 0x2091, + 0x8000, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000, + 0x2090, 0xaad5, 0x0000, 0x0120, 0x8421, 0x2200, 0x1904, 0x2612, + 0x0005, 0xd1dc, 0x0904, 0x35d5, 0x2029, 0x0020, 0xd69c, 0x1120, + 0x8528, 0xd68c, 0x1108, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, + 0xa18c, 0x00ff, 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0188, 0x6014, + 0xa706, 0x1dd0, 0x60b8, 0x8001, 0x60ba, 0x1d88, 0x2a60, 0x6008, + 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, 0x1904, 0x2612, 0x0005, + 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, 0x8840, 0x6008, 0xc0d5, + 0x600a, 0x77a4, 0xa786, 0x0001, 0x1904, 0x2698, 0x70d4, 0xd0b4, + 0x1904, 0x2698, 0x7000, 0xa082, 0x0002, 0x1a04, 0x2698, 0x7830, + 0xd0bc, 0x1904, 0x2698, 0x789b, 0x0080, 0x7baa, 0x7daa, 0x79aa, + 0x2001, 0x0002, 0x0006, 0x6018, 0x8000, 0x601a, 0x0008, 0x0006, + 0x2960, 0x6104, 0x2a60, 0x080c, 0x3b3b, 0x1590, 0xa184, 0x0018, + 0x0180, 0xa184, 0x0010, 0x0118, 0x080c, 0x3776, 0x1548, 0xa184, + 0x0008, 0x0138, 0x69a0, 0xa184, 0x0600, 0x1118, 0x080c, 0x3696, + 0x00f8, 0x69a0, 0xa184, 0x1e00, 0x0528, 0xa184, 0x0800, 0x0178, + 0x00c6, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, + 0x0010, 0x6106, 0x00ce, 0x080c, 0x3776, 0x1150, 0x69a0, 0xa184, + 0x0200, 0x0118, 0x080c, 0x36d9, 0x0018, 0xa184, 0x0400, 0x19f0, + 0x69a0, 0xa184, 0x1000, 0x0130, 0x6914, 0xa18c, 0xff00, 0x810f, + 0x080c, 0x231f, 0x002e, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0128, + 0xa086, 0x0060, 0x1110, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, + 0x789b, 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, + 0x0168, 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0328, 0xa08a, + 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, 0x78aa, 0x3518, + 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, 0x20a0, 0x789b, + 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, 0x2898, 0x25a0, + 0xa286, 0x0020, 0x1508, 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, + 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, 0x7882, 0xa286, 0x0002, + 0x0904, 0x27e0, 0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa498, 0x0005, + 0x70ac, 0xa306, 0x1108, 0x73a8, 0x73b6, 0xa286, 0x0010, 0x0904, + 0x248c, 0x00de, 0x00ce, 0x0005, 0x7000, 0xa005, 0x19e0, 0xa286, + 0x0002, 0x1904, 0x27f7, 0x080c, 0x3a8d, 0x19a8, 0x6814, 0xc0fc, + 0x8007, 0x7882, 0x2091, 0x8000, 0x781b, 0x0068, 0x68b4, 0x785a, + 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, + 0x7808, 0xc08d, 0x780a, 0x0126, 0x00d6, 0x00c6, 0x70d4, 0xa084, + 0x2e00, 0x2090, 0x00ce, 0x00de, 0x012e, 0x2900, 0x705a, 0x68bc, + 0x7042, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, + 0x7830, 0xd0bc, 0x0140, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, + 0x2091, 0x8000, 0x2090, 0x70a4, 0xa005, 0x1108, 0x0005, 0x8421, + 0x0de8, 0x7250, 0x70c0, 0xa200, 0xa015, 0x0804, 0x2612, 0xa286, + 0x0010, 0x1560, 0x080c, 0x3a8d, 0x1904, 0x278b, 0x6814, 0xc0fc, + 0x8007, 0x7882, 0x781b, 0x0068, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x70a4, + 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, 0xa206, 0x1108, + 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, 0x0002, + 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x0005, 0x6bb4, 0xa39d, + 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x6b94, 0x7bd6, + 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, 0x0068, 0x2900, 0x705a, + 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, 0xa605, 0x0170, 0x70d4, + 0xa084, 0x2e00, 0xa086, 0x2600, 0x1118, 0x2009, 0x0000, 0x0010, + 0x2009, 0x0001, 0xa284, 0x000f, 0x0023, 0xad80, 0x0009, 0x7046, + 0x0005, 0x2859, 0x3fb8, 0x3fb8, 0x3fa6, 0x3fb8, 0x2859, 0x2859, + 0x2859, 0x080c, 0x243b, 0x7808, 0xa084, 0xfffd, 0x780a, 0x00f6, + 0x2079, 0x4300, 0x78ac, 0x00fe, 0xd084, 0x01c0, 0x7064, 0xa086, + 0x0001, 0x1118, 0x7066, 0x0804, 0x293a, 0x7064, 0xa086, 0x0005, + 0x1158, 0x707c, 0x2068, 0x681b, 0x0004, 0x6817, 0x0000, 0x6820, + 0xa084, 0x00ff, 0xc09d, 0x6822, 0x7067, 0x0000, 0x70a7, 0x0000, + 0x70a8, 0x70b2, 0x70b6, 0x080c, 0x256f, 0x0156, 0x2011, 0x0004, + 0x7164, 0xa186, 0x0001, 0x0170, 0xa186, 0x0007, 0x1118, 0x701f, + 0x0005, 0x0040, 0x701f, 0x0001, 0x7067, 0x0000, 0x70d4, 0xc0c5, + 0x70d6, 0x0010, 0x7067, 0x0000, 0x2001, 0x430a, 0x2004, 0xa084, + 0x00ff, 0xa086, 0x0018, 0x0130, 0x7018, 0x7016, 0xa005, 0x1110, + 0x70a7, 0x0001, 0x0066, 0x080c, 0x3d52, 0x20a9, 0x0010, 0x2039, + 0x0000, 0x080c, 0x3861, 0xa7b8, 0x0100, 0x1f04, 0x28b1, 0x006e, + 0x7000, 0x0002, 0x28ee, 0x28cc, 0x28cc, 0x28c4, 0x28ee, 0x28ee, + 0x28ee, 0x28c2, 0x080c, 0x243b, 0x7060, 0xa005, 0x0538, 0xad06, + 0x1118, 0x6800, 0x7062, 0x0080, 0x6820, 0xd084, 0x1148, 0x6f14, + 0x080c, 0x396d, 0x6008, 0xc0d4, 0x600a, 0x080c, 0x35ab, 0x0020, + 0x705c, 0x2060, 0x6800, 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, + 0xd0fc, 0x0108, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x6820, + 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, 0x1d3d, 0xb284, 0x0800, + 0x0118, 0x2021, 0x8ad0, 0x0010, 0x2021, 0x89c0, 0x080c, 0x293f, + 0xb284, 0x0800, 0x0118, 0x2021, 0x4398, 0x0010, 0x2021, 0x4358, + 0x04f1, 0x20a9, 0x0101, 0xb284, 0x0800, 0x0118, 0x2021, 0x89d0, + 0x0010, 0x2021, 0x88c0, 0x0499, 0x8420, 0x1f04, 0x290b, 0xb284, + 0x0600, 0x0118, 0x2061, 0x48c0, 0x0010, 0x2061, 0x68c0, 0x2021, + 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0198, 0x6018, 0x0016, + 0x0006, 0x2011, 0x4302, 0x220c, 0xa102, 0x2012, 0x000e, 0x001e, + 0xa102, 0x0338, 0x6012, 0x1128, 0x2011, 0x4304, 0x2204, 0xc0a5, + 0x2012, 0x601b, 0x0000, 0xace0, 0x0010, 0x1f04, 0x291b, 0x8421, + 0x1d00, 0x015e, 0x7003, 0x0000, 0x704f, 0x0000, 0x0005, 0x0046, + 0x2404, 0xa005, 0x01a8, 0x2068, 0x6800, 0x0006, 0x6a1a, 0x6817, + 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, + 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, 0x1d3d, 0x000e, 0x0c48, + 0x004e, 0x2023, 0x0000, 0x0005, 0xa282, 0x0003, 0x0310, 0x080c, + 0x243b, 0x2300, 0x0002, 0x2966, 0x29e3, 0x29fd, 0xa282, 0x0002, + 0x0110, 0x080c, 0x243b, 0x7064, 0x7067, 0x0000, 0x7083, 0x0000, + 0x0022, 0x77d4, 0xc7c5, 0x77d6, 0x0002, 0x297d, 0x297d, 0x297f, + 0x29b7, 0x35df, 0x297d, 0x29b7, 0x297d, 0x080c, 0x243b, 0x7774, + 0x080c, 0x3861, 0x7774, 0xa7bc, 0x8f00, 0x080c, 0x396d, 0x6018, + 0xa005, 0x0528, 0xd7fc, 0x1118, 0x2021, 0x89c0, 0x0010, 0x2021, + 0x8ad0, 0x2009, 0x0005, 0x2011, 0x0010, 0x080c, 0x2a17, 0x01b8, + 0x0156, 0x20a9, 0x0101, 0xd7fc, 0x1118, 0x2021, 0x88c0, 0x0010, + 0x2021, 0x89d0, 0x0046, 0x2009, 0x0005, 0x2011, 0x0010, 0x080c, + 0x2a17, 0x004e, 0x0118, 0x8420, 0x1f04, 0x29a2, 0x015e, 0x8738, + 0xa784, 0x001f, 0x1990, 0x0804, 0x248f, 0x0804, 0x248f, 0x7774, + 0x080c, 0x396d, 0x6018, 0xa005, 0x0520, 0xd7fc, 0x1118, 0x2021, + 0x89c0, 0x0010, 0x2021, 0x8ad0, 0x2009, 0x0005, 0x2011, 0x0020, + 0x080c, 0x2a17, 0x01b0, 0x0156, 0x20a9, 0x0101, 0xd7fc, 0x1118, + 0x2021, 0x88c0, 0x0010, 0x2021, 0x89d0, 0x0046, 0x2009, 0x0005, + 0x2011, 0x0020, 0x04e1, 0x004e, 0x0118, 0x8420, 0x1f04, 0x29d5, + 0x015e, 0x0804, 0x248f, 0x2200, 0x0002, 0x29e8, 0x29ea, 0x29ea, + 0x080c, 0x243b, 0x2009, 0x0012, 0x7064, 0xa086, 0x0002, 0x0110, + 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0108, 0x691a, 0x7067, 0x0000, + 0x70d4, 0xc0c5, 0x70d6, 0x0804, 0x3a3f, 0x2200, 0x0002, 0x2a04, + 0x29ea, 0x2a02, 0x080c, 0x243b, 0x080c, 0x3d52, 0x7000, 0xa086, + 0x0002, 0x1904, 0x356d, 0x080c, 0x35c5, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x080c, 0x355f, 0x0904, 0x356d, 0x0804, 0x248f, 0x2404, + 0xa005, 0x0590, 0x2068, 0x2d04, 0x0006, 0x6814, 0xa706, 0x0118, + 0x2d20, 0x000e, 0x0ca8, 0x000e, 0x2022, 0x691a, 0x6817, 0x0000, + 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, + 0x00ff, 0xa205, 0x6822, 0x080c, 0x1d3d, 0x2021, 0x4302, 0x241c, + 0x8319, 0x2322, 0x6010, 0x8001, 0x6012, 0x1128, 0x2021, 0x4304, + 0x2404, 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, 0x080c, + 0x258b, 0x080c, 0x35c5, 0x0005, 0xa085, 0x0001, 0x0ce0, 0x2300, + 0x0002, 0x2a56, 0x2a54, 0x2abc, 0x080c, 0x243b, 0x78e4, 0xa005, + 0x1708, 0x3208, 0xa18c, 0x0800, 0x0118, 0x0104, 0x248c, 0x0010, + 0x0304, 0x248c, 0x2008, 0xa084, 0x0030, 0x1110, 0x0804, 0x30a0, + 0x78ec, 0xa084, 0x0003, 0x0dd0, 0x2100, 0xa084, 0x0007, 0x0002, + 0x2a9f, 0x2aa8, 0x2a95, 0x2a78, 0x3a83, 0x3a83, 0x2a78, 0x2ab2, + 0x080c, 0x243b, 0x7000, 0xa086, 0x0004, 0x1190, 0x7064, 0xa086, + 0x0002, 0x1130, 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, 0x295c, + 0x7064, 0xa086, 0x0006, 0x0db0, 0x7064, 0xa086, 0x0004, 0x0d90, + 0x79e4, 0x2001, 0x0003, 0x0804, 0x2daa, 0x6818, 0xd0fc, 0x0110, + 0x681b, 0x001d, 0x080c, 0x3837, 0x781b, 0x006e, 0x0005, 0x6818, + 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3837, 0x0804, 0x3a61, + 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3837, 0x781b, + 0x00fa, 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, + 0x3837, 0x781b, 0x00cb, 0x0005, 0xa584, 0x000f, 0x11c0, 0x7000, + 0x0002, 0x248f, 0x2ac9, 0x2acb, 0x356d, 0x356d, 0x356d, 0x2ac9, + 0x2ac9, 0x080c, 0x243b, 0x080c, 0x35c5, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x080c, 0x355f, 0x0904, 0x356d, 0x0804, 0x248f, 0x78e4, + 0xa005, 0x1b04, 0x2a7a, 0x3208, 0xa18c, 0x0800, 0x0118, 0x0104, + 0x2a7a, 0x0010, 0x0304, 0x2a7a, 0x2008, 0xa084, 0x0030, 0x1118, + 0x781b, 0x0068, 0x0005, 0x78ec, 0xa084, 0x0003, 0x0dc8, 0x2100, + 0xa184, 0x0007, 0x0002, 0x2b02, 0x2b06, 0x2afd, 0x2afb, 0x3a83, + 0x3a83, 0x2afb, 0x3a7d, 0x080c, 0x243b, 0x080c, 0x383d, 0x781b, + 0x006e, 0x0005, 0x080c, 0x383d, 0x0804, 0x3a61, 0x080c, 0x383d, + 0x781b, 0x00fa, 0x0005, 0x080c, 0x383d, 0x781b, 0x00cb, 0x0005, + 0x2300, 0x0002, 0x2b17, 0x2b15, 0x2b19, 0x080c, 0x243b, 0x0804, + 0x3220, 0x681b, 0x0016, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, + 0x0904, 0x3220, 0x78ec, 0xa084, 0x0003, 0x0904, 0x3220, 0xa184, + 0x0100, 0x0d98, 0xa184, 0x0007, 0x0002, 0x2b35, 0x2b06, 0x2a95, + 0x3a3f, 0x3a83, 0x3a83, 0x3a3f, 0x3a7d, 0x080c, 0x3a4b, 0x0005, + 0xa282, 0x0005, 0x0310, 0x080c, 0x243b, 0x7898, 0x2040, 0x2300, + 0x0002, 0x2b44, 0x2d41, 0x2d4b, 0x2200, 0x0002, 0x2b60, 0x2b4d, + 0x2b60, 0x2b4b, 0x2d25, 0x080c, 0x243b, 0x789b, 0x0018, 0x78a8, + 0x2010, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0a04, 0x3809, 0xa08a, + 0x0004, 0x1a04, 0x3809, 0x0002, 0x3809, 0x3809, 0x3809, 0x37bf, + 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0148, 0x0804, 0x3809, + 0x7000, 0xa005, 0x1dd8, 0x2011, 0x0004, 0x0804, 0x33b2, 0xa184, + 0x00ff, 0xa08a, 0x0010, 0x1a04, 0x3809, 0x0002, 0x2b88, 0x2b86, + 0x2b9a, 0x2b9e, 0x2c3c, 0x3809, 0x3809, 0x2c3e, 0x3809, 0x3809, + 0x2d21, 0x2d21, 0x3809, 0x3809, 0x3809, 0x2d23, 0x080c, 0x243b, + 0xd6e4, 0x0140, 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, + 0x00c6, 0x0005, 0x6818, 0xd0fc, 0x0118, 0x681b, 0x001d, 0x0c90, + 0x0804, 0x3a3f, 0x681b, 0x001d, 0x0804, 0x3831, 0x6920, 0x6922, + 0xa684, 0x1800, 0x15e0, 0x6820, 0xd084, 0x1904, 0x2be7, 0x6818, + 0xa086, 0x0008, 0x1110, 0x681b, 0x0000, 0xd6d4, 0x0568, 0xd6bc, + 0x0558, 0x7087, 0x0000, 0x6818, 0xa084, 0x003f, 0xa08a, 0x000d, + 0x0718, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, + 0x789b, 0x0061, 0x78aa, 0x0156, 0x0136, 0x0146, 0x0016, 0x3208, + 0xa18c, 0x0600, 0x0118, 0x20a1, 0x022b, 0x0010, 0x20a1, 0x012b, + 0x001e, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, + 0x53a6, 0x014e, 0x013e, 0x015e, 0x781b, 0x0071, 0x0005, 0xd6e4, + 0x0130, 0x781b, 0x0083, 0x0005, 0x781b, 0x0083, 0x0005, 0xa684, + 0x0060, 0x0dd0, 0xd6dc, 0x0dc0, 0xd6fc, 0x01a0, 0xc6fc, 0x7e5a, + 0x6eb6, 0x7adc, 0x79d8, 0x78d0, 0x8007, 0xa084, 0x007f, 0xa108, + 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, + 0xa303, 0x68ae, 0xd6f4, 0x0118, 0xc6f4, 0x7e5a, 0x6eb6, 0x7000, + 0xa086, 0x0003, 0x1148, 0x0006, 0x080c, 0x3d52, 0x080c, 0x3fb8, + 0x000e, 0x781b, 0x0080, 0x0005, 0xa006, 0x080c, 0x4083, 0x6ab0, + 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0120, 0x2200, 0xa422, + 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, 0x7bde, + 0x2300, 0xa405, 0x1130, 0xc6f5, 0x7e5a, 0x6eb6, 0x781b, 0x0080, + 0x0005, 0x781b, 0x0080, 0x2200, 0xa115, 0x1118, 0x080c, 0x3fb8, + 0x0005, 0x080c, 0x3fe5, 0x0005, 0x080c, 0x243b, 0x0804, 0x2cbd, + 0x00c6, 0x7058, 0x2060, 0x7aa8, 0xa294, 0x00ff, 0xa286, 0x0004, + 0x11d8, 0x6920, 0xd1e4, 0x1170, 0x2039, 0x0000, 0x2041, 0x0000, + 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x36f6, 0x080c, 0x379a, + 0x0804, 0x2cb1, 0xa18c, 0xecff, 0x6922, 0x6104, 0xa18c, 0xffdd, + 0x6106, 0x6000, 0xc0ac, 0x6002, 0xa286, 0x0003, 0x01d0, 0x6104, + 0xa18c, 0x0010, 0x0548, 0x080c, 0x3969, 0x080c, 0x3776, 0x88ff, + 0x0518, 0x00ce, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, + 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, + 0x0005, 0x6920, 0xd1cc, 0x0130, 0xa18c, 0xfdff, 0x6922, 0x6000, + 0xc0ec, 0x6002, 0x2039, 0x0000, 0x2041, 0x0000, 0x2031, 0x0000, + 0xa006, 0x2010, 0x080c, 0x379a, 0xa286, 0x0001, 0x0158, 0x6104, + 0xa18c, 0x0008, 0x01b0, 0x080c, 0x3969, 0x080c, 0x3696, 0x88ff, + 0x1980, 0x0078, 0x6920, 0xd1c4, 0x0130, 0xa18c, 0xfeff, 0x6922, + 0x6000, 0xc0e4, 0x6002, 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, + 0x36f6, 0x00ce, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, + 0x781b, 0x0083, 0x0005, 0x0804, 0x382d, 0x2808, 0x789b, 0x0080, + 0x2019, 0x0080, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x1188, + 0x7ca8, 0xa4a4, 0x00ff, 0xa480, 0x0002, 0xa300, 0x2018, 0xa102, + 0x0a04, 0x2c40, 0x0904, 0x2c40, 0x24a8, 0x7aa8, 0x1f04, 0x2cd5, + 0x0c48, 0xa284, 0x00f0, 0xa082, 0x0020, 0x06b8, 0x2200, 0xa082, + 0x0021, 0x1698, 0x7aa8, 0x8318, 0x8318, 0x2100, 0xa302, 0x0ad0, + 0xa286, 0x0023, 0x0980, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, + 0xa684, 0xfff1, 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, + 0x78a0, 0x8001, 0x0904, 0x2cb1, 0x20a8, 0x7998, 0x789b, 0x0060, + 0x78aa, 0x2011, 0x0080, 0x799a, 0x78a8, 0x7998, 0x7a9a, 0x78aa, + 0x7a98, 0x1f04, 0x2d03, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, + 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x8318, 0x2100, 0xa302, + 0x0a04, 0x2cc2, 0xa284, 0x0080, 0x1904, 0x3831, 0x78a0, 0xa005, + 0x08c8, 0x0804, 0x3831, 0x0804, 0x3809, 0x7058, 0xa04d, 0x789b, + 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0110, 0x080c, + 0x243b, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, + 0x0005, 0x1a04, 0x3809, 0x0002, 0x3809, 0x3615, 0x3809, 0x3726, + 0x3b83, 0xa282, 0x0000, 0x1110, 0x080c, 0x243b, 0x080c, 0x3837, + 0x781b, 0x0082, 0x0005, 0xa282, 0x0003, 0x1110, 0x080c, 0x243b, + 0xd4fc, 0x11d0, 0x7064, 0xa005, 0x0110, 0x080c, 0x243b, 0x6f14, + 0x7776, 0xa7bc, 0x8f00, 0x080c, 0x396d, 0x6008, 0xa085, 0x0021, + 0x600a, 0x8738, 0xa784, 0x001f, 0x1db0, 0x080c, 0x383a, 0x7067, + 0x0002, 0x701f, 0x0009, 0x0010, 0x080c, 0x3846, 0x781b, 0x0082, + 0x0005, 0xa282, 0x0004, 0x0310, 0x080c, 0x243b, 0x2300, 0x0002, + 0x2d7b, 0x2eff, 0x2f3b, 0xa286, 0x0003, 0x0560, 0x7200, 0x7cd8, + 0x7ddc, 0x7fd0, 0x71d4, 0xd1b4, 0x00f0, 0x7868, 0xa084, 0x00ff, + 0x11d0, 0xa282, 0x0002, 0x12b8, 0x00d6, 0x783b, 0x8300, 0x781b, + 0x0059, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, + 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x00de, + 0x2001, 0x0000, 0x0058, 0x783b, 0x1300, 0x781b, 0x0057, 0x2001, + 0x0000, 0x0020, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x704a, 0x68a0, + 0xd0ec, 0x0118, 0x6008, 0xc08d, 0x600a, 0xa284, 0x000f, 0x0002, + 0x2ee0, 0x2dc5, 0x2dc2, 0x3012, 0x3085, 0x248f, 0x2dc0, 0x2dc0, + 0x080c, 0x243b, 0x6008, 0xc0d4, 0x600a, 0xd6e4, 0x0120, 0x7048, + 0xa086, 0x0014, 0x11e8, 0x080c, 0x3d52, 0x2009, 0x0000, 0x6818, + 0xd0fc, 0x0108, 0x7048, 0xa086, 0x0014, 0x0168, 0x6818, 0xa086, + 0x0008, 0x1904, 0x2ea2, 0x7858, 0xd09c, 0x0904, 0x2ea2, 0x6820, + 0xd0ac, 0x0904, 0x2ea2, 0x681b, 0x0014, 0x2009, 0x0002, 0x04a8, + 0x7868, 0xa08c, 0x00ff, 0x0588, 0xa186, 0x0008, 0x1158, 0x6008, + 0xc0a4, 0x600a, 0x080c, 0x355f, 0x0540, 0x080c, 0x35c5, 0x080c, + 0x3d52, 0x0060, 0xa186, 0x0028, 0x1500, 0x6018, 0xa005, 0x0d78, + 0x8001, 0x0d68, 0x8001, 0x0d58, 0x601e, 0x0c48, 0x6820, 0xd084, + 0x0904, 0x248f, 0xc084, 0x6822, 0x080c, 0x2580, 0x705c, 0x00c6, + 0x2060, 0x6800, 0x6002, 0x00ce, 0x6004, 0x6802, 0xa005, 0x2d00, + 0x1108, 0x6002, 0x6006, 0x0804, 0x248f, 0x0016, 0x81ff, 0x15e0, + 0x7000, 0xa086, 0x0030, 0x05c0, 0x71d4, 0xd1b4, 0x11e8, 0x7060, + 0xa005, 0x1590, 0x70a4, 0xa086, 0x0001, 0x0570, 0x7003, 0x0000, + 0x0046, 0x0056, 0x0076, 0x0066, 0x00c6, 0x00d6, 0x080c, 0x24b2, + 0x00de, 0x00ce, 0x006e, 0x007e, 0x005e, 0x004e, 0x71d4, 0xd1b4, + 0x11d8, 0x7003, 0x0040, 0x00c0, 0x080c, 0x3a8d, 0x11a8, 0x781b, + 0x0068, 0x00d6, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, + 0x7808, 0xc08d, 0x780a, 0x00de, 0x080c, 0x2f63, 0x001e, 0x81ff, + 0x0904, 0x2ea2, 0xa684, 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14, + 0xa186, 0x0002, 0x15c0, 0x6818, 0xa086, 0x0014, 0x1130, 0x2008, + 0xd6e4, 0x0118, 0x7868, 0xa08c, 0x00ff, 0x080c, 0x3850, 0x080c, + 0x258b, 0x6820, 0xd0dc, 0x1538, 0x8717, 0xa294, 0x000f, 0x8213, + 0x8213, 0x8213, 0xb284, 0x0600, 0x0118, 0xa290, 0x47c0, 0x0010, + 0xa290, 0x4840, 0xa290, 0x0000, 0x221c, 0xd3c4, 0x0130, 0x8210, + 0x2204, 0xa085, 0x0038, 0x2012, 0x8211, 0xd3d4, 0x0138, 0x68a0, + 0xd0c4, 0x1120, 0x080c, 0x2fcb, 0x0804, 0x248f, 0x6008, 0xc08d, + 0x600a, 0x0008, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0110, 0x7048, + 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, 0x0168, 0x2009, + 0x4302, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, 0x1128, 0x2021, + 0x4304, 0x2404, 0xc0a5, 0x2022, 0x6018, 0xa005, 0x0118, 0x8001, + 0x601a, 0x1118, 0x6008, 0xc0a4, 0x600a, 0x6820, 0xd084, 0x1130, + 0x6800, 0xa005, 0x1108, 0x6002, 0x6006, 0x0020, 0x705c, 0x2060, + 0x6800, 0x6002, 0x2061, 0x4300, 0x6887, 0x0103, 0x2d08, 0x206b, + 0x0000, 0x6068, 0xa005, 0x616a, 0x0110, 0x2d02, 0x0008, 0x616e, + 0x7200, 0xa286, 0x0030, 0x0158, 0xa286, 0x0040, 0x1904, 0x248f, + 0x7003, 0x0002, 0x704c, 0x2068, 0x68c4, 0x2060, 0x0005, 0x7003, + 0x0002, 0x70bc, 0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, 0x68c0, + 0x705a, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x0005, 0xa282, + 0x0004, 0x0210, 0x080c, 0x243b, 0x2200, 0x0002, 0x2f0a, 0x2f19, + 0x2f25, 0x2f19, 0xa586, 0x1300, 0x0160, 0xa586, 0x8300, 0x1d90, + 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x7000, 0xa086, 0x0005, 0x0128, 0x080c, 0x3837, 0x781b, + 0x0082, 0x0005, 0x781b, 0x0083, 0x0005, 0x7890, 0x8007, 0x8001, + 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, + 0xa186, 0x0003, 0x0128, 0xa186, 0x0000, 0x0110, 0x0804, 0x3809, + 0x781b, 0x0083, 0x0005, 0x6820, 0xc095, 0x6822, 0x82ff, 0x1118, + 0x080c, 0x3837, 0x0030, 0x8211, 0x0110, 0x080c, 0x243b, 0x080c, + 0x3846, 0x781b, 0x0082, 0x0005, 0x080c, 0x3aa0, 0x7830, 0xa084, + 0x00c0, 0x1170, 0x0016, 0x3208, 0xa18c, 0x0800, 0x001e, 0x0118, + 0x0104, 0x2f60, 0x0010, 0x0304, 0x2f60, 0x791a, 0xa006, 0x0005, + 0xa085, 0x0001, 0x0005, 0xa684, 0x0060, 0x1130, 0x682f, 0x0000, + 0x6833, 0x0000, 0x0804, 0x2fca, 0xd6dc, 0x1198, 0x68b4, 0xd0dc, + 0x1180, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, 0xa005, 0x1130, + 0x2200, 0xa105, 0x0904, 0x3d52, 0x704b, 0x0015, 0x0804, 0x3d52, + 0x0005, 0xd6ac, 0x01f0, 0xd6f4, 0x0130, 0x682f, 0x0000, 0x6833, + 0x0000, 0x0804, 0x3d52, 0x68b4, 0xa084, 0x4000, 0xa635, 0xd6f4, + 0x1da0, 0x7048, 0xa005, 0x1110, 0x704b, 0x0015, 0xd6dc, 0x1128, + 0x68b4, 0xd0dc, 0x0110, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0804, + 0x3d52, 0xd6f4, 0x0130, 0x682f, 0x0000, 0x6833, 0x0000, 0x0804, + 0x3d52, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x1da0, 0x7048, + 0xa005, 0x1110, 0x704b, 0x0015, 0x2408, 0x2510, 0x2700, 0x8007, + 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, + 0xa205, 0x1110, 0x0804, 0x3d52, 0x7000, 0xa086, 0x0006, 0x0110, + 0x0804, 0x3d52, 0x0005, 0x6946, 0x6008, 0xc0cd, 0xd3cc, 0x0108, + 0xc08d, 0x600a, 0x6818, 0x683a, 0x681b, 0x0006, 0x688f, 0x0000, + 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, + 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, + 0x7000, 0x0002, 0x248f, 0x2ffa, 0x2ff4, 0x2ff2, 0x2ff2, 0x2ff2, + 0x2ff2, 0x2ff2, 0x080c, 0x243b, 0x6820, 0xd084, 0x1118, 0x080c, + 0x35ab, 0x0030, 0x705c, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, + 0x3208, 0xa18c, 0x0600, 0x0118, 0x2021, 0x4358, 0x0010, 0x2021, + 0x4398, 0x2404, 0xa005, 0x0110, 0x2020, 0x0cd8, 0x2d22, 0x206b, + 0x0000, 0x0005, 0x080c, 0x35b1, 0x080c, 0x35c5, 0x6008, 0xc0cc, + 0x600a, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x6938, 0x691a, + 0x6944, 0x6916, 0x3208, 0xa18c, 0x0600, 0x0118, 0x2009, 0x0000, + 0x0010, 0x2009, 0x0001, 0x080c, 0x40b1, 0xd6dc, 0x0118, 0x691c, + 0xc1ed, 0x691e, 0x6818, 0xd0fc, 0x0148, 0x7868, 0xa08c, 0x00ff, + 0x0118, 0x681b, 0x001e, 0x0010, 0x681b, 0x0000, 0xb284, 0x0600, + 0x1118, 0x2021, 0x4398, 0x0010, 0x2021, 0x4358, 0x6800, 0x2022, + 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x68c0, 0x2060, 0x6000, 0xd0a4, + 0x0580, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x00d6, + 0x00f6, 0x0156, 0x0146, 0x2079, 0x4300, 0x080c, 0x1b35, 0x014e, + 0x015e, 0x00fe, 0x70cc, 0x2010, 0x2009, 0x0101, 0x0026, 0x2204, + 0xa06d, 0x0140, 0x6814, 0xa706, 0x0110, 0x6800, 0x0cc8, 0x6820, + 0xc0d5, 0x6822, 0x002e, 0x8210, 0x8109, 0x1d80, 0x00de, 0x7067, + 0x0003, 0x707f, 0x0000, 0x7776, 0x7083, 0x000f, 0x71d4, 0xc1c4, + 0x71d6, 0x080c, 0x1d3d, 0x0804, 0x248f, 0x7cd8, 0x7ddc, 0x7fd0, + 0x080c, 0x2f63, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x080c, + 0x3aa4, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xd0fc, 0x0110, 0x7048, + 0x681a, 0xa68c, 0xdf00, 0x691e, 0x7067, 0x0000, 0x0804, 0x248f, + 0x7000, 0xa005, 0x1110, 0x0804, 0x248f, 0xa006, 0x080c, 0x3d52, + 0x6920, 0xd1ac, 0x1110, 0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, + 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, 0x6822, 0x7000, 0x0002, + 0x248f, 0x30c2, 0x30c2, 0x30c5, 0x30c5, 0x30c5, 0x30c0, 0x30c0, + 0x080c, 0x243b, 0x6818, 0x0804, 0x2daa, 0x6008, 0xc0a4, 0x600a, + 0x6817, 0x0000, 0x0804, 0x357a, 0x2300, 0x0002, 0x30d1, 0x30d3, + 0x3110, 0x080c, 0x243b, 0xd6fc, 0x1904, 0x2bee, 0x7000, 0xa00d, + 0x0002, 0x248f, 0x30e3, 0x30e3, 0x3104, 0x30e3, 0x310d, 0x30e1, + 0x30e1, 0x080c, 0x243b, 0xa684, 0x0060, 0xa086, 0x0060, 0x11d0, + 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x681c, 0xc0ac, 0x681e, 0xa186, + 0x0002, 0x0110, 0x080c, 0x3d52, 0x080c, 0x3fb8, 0x781b, 0x0083, + 0x71d4, 0xd1b4, 0x1904, 0x248c, 0x70a4, 0xa086, 0x0001, 0x1904, + 0x24ce, 0x0005, 0xd6ec, 0x0d30, 0x6818, 0xd0fc, 0x0130, 0x681b, + 0x0015, 0xd6f4, 0x0110, 0x681b, 0x0007, 0x080c, 0x3a4b, 0x0005, + 0x080c, 0x243b, 0x2300, 0x0002, 0x3119, 0x3134, 0x3182, 0x080c, + 0x243b, 0x7000, 0x0002, 0x3123, 0x3125, 0x3125, 0x3123, 0x3123, + 0x3123, 0x3123, 0x3123, 0x080c, 0x243b, 0x080c, 0x3fb8, 0x681c, + 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x1904, 0x248c, 0x70a4, 0xa086, + 0x0001, 0x1904, 0x24ce, 0x0005, 0xd6fc, 0x15e0, 0x7000, 0xa00d, + 0x0002, 0x248f, 0x3149, 0x3143, 0x316a, 0x3149, 0x316f, 0x3141, + 0x3141, 0x080c, 0x243b, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, + 0x78da, 0xa684, 0x0060, 0xa086, 0x0060, 0x11d0, 0xa6b4, 0xbfbf, + 0xc6ed, 0x7e5a, 0xa186, 0x0002, 0x0110, 0x080c, 0x3d52, 0x080c, + 0x3fb8, 0x781b, 0x0083, 0x681c, 0xc0b4, 0x681e, 0x71d4, 0xd1b4, + 0x1904, 0x248c, 0x70a4, 0xa086, 0x0001, 0x1904, 0x24ce, 0x0005, + 0xd6ec, 0x0d30, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x0007, 0x781b, + 0x00fb, 0x0005, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, 0x2100, + 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, 0x781b, + 0x0083, 0x0005, 0xd6dc, 0x0130, 0x782b, 0x3009, 0x781b, 0x0083, + 0x0804, 0x248c, 0x7884, 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, + 0x1150, 0xa484, 0x0200, 0x0108, 0xc6f5, 0xc6dd, 0x7e5a, 0x781b, + 0x0083, 0x0804, 0x248c, 0x6820, 0xc095, 0x6822, 0x080c, 0x39ca, + 0xc6dd, 0x080c, 0x3837, 0x781b, 0x0082, 0x0804, 0x248c, 0x2300, + 0x0002, 0x31ac, 0x31ae, 0x31b0, 0x080c, 0x243b, 0x0804, 0x3831, + 0x7d98, 0xd6d4, 0x11f8, 0x79e4, 0xd1ac, 0x0130, 0x78ec, 0xa084, + 0x0003, 0x0110, 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, + 0xa684, 0xfffb, 0x785a, 0x7d9a, 0x79e4, 0xd1ac, 0x0120, 0x78ec, + 0xa084, 0x0003, 0x1120, 0x2001, 0x0014, 0x0804, 0x2daa, 0xa184, + 0x0007, 0x04c2, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, + 0x81ff, 0x0568, 0x789b, 0x0080, 0x7ba8, 0xa384, 0x0001, 0x11d0, + 0x7ba8, 0x7ba8, 0xa386, 0x0004, 0x1118, 0x2009, 0xffdf, 0x0058, + 0xa386, 0x0001, 0x1118, 0x2009, 0xfff7, 0x0028, 0xa386, 0x0003, + 0x1148, 0x2009, 0xffef, 0x00c6, 0x7058, 0x2060, 0x6004, 0xa104, + 0x6006, 0x00ce, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, + 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xecff, 0x6922, 0x7d9a, + 0x0804, 0x3a3f, 0x2a9f, 0x2aa8, 0x3214, 0x321a, 0x3212, 0x3212, + 0x3a3f, 0x3a3f, 0x080c, 0x243b, 0x6920, 0xa18c, 0xfcff, 0x6922, + 0x0804, 0x3a45, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0804, 0x3a3f, + 0x79e4, 0xa184, 0x0030, 0x0120, 0x78ec, 0xa084, 0x0003, 0x1558, + 0x7000, 0xa086, 0x0004, 0x1190, 0x7064, 0xa086, 0x0002, 0x1130, + 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, 0x295c, 0x7064, 0xa086, + 0x0006, 0x0db0, 0x7064, 0xa086, 0x0004, 0x0d90, 0x7000, 0xa086, + 0x0000, 0x0904, 0x248c, 0x6920, 0xa184, 0x0420, 0x0128, 0xc1d4, + 0x6922, 0x6818, 0x0804, 0x2daa, 0x6818, 0xc0fd, 0x681a, 0x2001, + 0x0014, 0x0804, 0x2daa, 0xa184, 0x0007, 0x0002, 0x3a3f, 0x3a3f, + 0x325e, 0x3a3f, 0x3a83, 0x3a83, 0x3a3f, 0x3a3f, 0xd6bc, 0x0570, + 0x7184, 0x81ff, 0x0558, 0xa182, 0x000d, 0x1318, 0x7087, 0x0000, + 0x0028, 0xa182, 0x000c, 0x7086, 0x2009, 0x000c, 0x789b, 0x0061, + 0x79aa, 0x0156, 0x0136, 0x0146, 0x7088, 0x8114, 0xa210, 0x728a, + 0xa080, 0x000b, 0xad00, 0x2098, 0xb284, 0x0600, 0x0118, 0x20a1, + 0x022b, 0x0010, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, + 0x53a6, 0x014e, 0x013e, 0x015e, 0x0804, 0x3a45, 0xd6d4, 0x1904, + 0x32d1, 0x6820, 0xd084, 0x0904, 0x3a45, 0xa68c, 0x0060, 0xa684, + 0x0060, 0x0120, 0xa086, 0x0060, 0x1108, 0xc1f5, 0xc194, 0x795a, + 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, + 0xc0fd, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0904, 0x35da, 0xa18c, + 0x00f8, 0x1904, 0x35da, 0x0156, 0x0136, 0x0146, 0x0016, 0x20a1, + 0x012b, 0x3208, 0xa18c, 0x0600, 0x0110, 0x20a1, 0x022b, 0x001e, + 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, + 0x014e, 0x013e, 0x015e, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x0804, + 0x3a45, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x0008, 0x080c, 0x3837, + 0x781b, 0x00ed, 0x0005, 0x2300, 0x0002, 0x32e2, 0x3398, 0x32e0, + 0x080c, 0x243b, 0x7cd8, 0x7ddc, 0x7fd0, 0x82ff, 0x11f0, 0x7200, + 0xa286, 0x0003, 0x0904, 0x2d7f, 0x71d4, 0xd1b4, 0x00c0, 0x00d6, + 0x783b, 0x8800, 0x781b, 0x0059, 0x70bc, 0xa06d, 0x68b4, 0xc0a5, + 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, + 0x71d6, 0x7003, 0x0030, 0x00de, 0x0030, 0x7200, 0x0020, 0x783b, + 0x1800, 0x781b, 0x0057, 0xa284, 0x000f, 0x0002, 0x3383, 0x3344, + 0x3318, 0x2da7, 0x3316, 0x3383, 0x3316, 0x3316, 0x080c, 0x243b, + 0x681c, 0xd0ec, 0x0118, 0x6008, 0xc08d, 0x600a, 0x6920, 0xc185, + 0x6922, 0x6800, 0x6006, 0xa005, 0x1108, 0x6002, 0x6008, 0xc0d4, + 0x600a, 0x681c, 0xa084, 0x000e, 0x1148, 0xb284, 0x0600, 0x0118, + 0x2009, 0x89c0, 0x0040, 0x2009, 0x8ad0, 0x0028, 0x7030, 0x68ba, + 0x7140, 0x70cc, 0xa108, 0x2104, 0x6802, 0x2d0a, 0x715e, 0xd6dc, + 0x1118, 0xc6fc, 0x6eb6, 0x04f8, 0x6eb6, 0xa684, 0x0060, 0x05d8, + 0xd6dc, 0x1150, 0xa684, 0x7fff, 0x68b6, 0x6894, 0x68a6, 0x6898, + 0x68aa, 0x080c, 0x3d52, 0x0478, 0xd6ac, 0x0140, 0xa006, 0x080c, + 0x3d52, 0x2408, 0x2510, 0x69aa, 0x6aa6, 0x0068, 0x2408, 0x2510, + 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x69aa, + 0x6aa6, 0x080c, 0x3d52, 0xd6fc, 0x01b0, 0xa684, 0x7fff, 0x68b6, + 0x2510, 0x2408, 0xd6ac, 0x1138, 0x2700, 0x8007, 0xa084, 0x007f, + 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, + 0x2200, 0xa303, 0x68ae, 0x7000, 0xa086, 0x0030, 0x1904, 0x248f, + 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, + 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x0005, + 0xa586, 0x8800, 0x1148, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x0804, 0x3831, 0x7047, 0x0000, + 0xa282, 0x0006, 0x0310, 0x080c, 0x243b, 0x2300, 0x0002, 0x33b2, + 0x33e4, 0x340f, 0x2200, 0x0002, 0x33ba, 0x3831, 0x33bc, 0x33ba, + 0x343f, 0x349d, 0x080c, 0x243b, 0x7003, 0x0005, 0xb284, 0x0600, + 0x0118, 0x2001, 0x8ae0, 0x0010, 0x2001, 0x8b12, 0x2068, 0x704e, + 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x1f04, 0x33cb, + 0x015e, 0xb284, 0x0600, 0x0118, 0x6817, 0x0000, 0x0010, 0x6817, + 0x8000, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, 0x0800, + 0x6827, 0x0003, 0x0804, 0x3809, 0x7000, 0xa086, 0x0002, 0x1150, + 0x080c, 0x35c5, 0x0010, 0x080c, 0x3d52, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x0020, 0x7000, 0xa086, 0x0003, 0x0da8, 0x7003, 0x0005, + 0xb284, 0x0600, 0x0118, 0x2001, 0x8ae0, 0x0010, 0x2001, 0x8b12, + 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, 0x2200, 0x0002, 0x3831, + 0x340d, 0x340d, 0x343f, 0x340d, 0x3831, 0x080c, 0x243b, 0x7000, + 0xa086, 0x0002, 0x1150, 0x080c, 0x35c5, 0x0010, 0x080c, 0x3d52, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x0020, 0x7000, 0xa086, 0x0003, + 0x0da8, 0x7003, 0x0005, 0xb284, 0x0600, 0x0118, 0x2001, 0x8ae0, + 0x0010, 0x2001, 0x8b12, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, + 0x2200, 0x0002, 0x343a, 0x3438, 0x3438, 0x343a, 0x3438, 0x343a, + 0x080c, 0x243b, 0x080c, 0x3846, 0x781b, 0x0082, 0x0005, 0x7000, + 0xa086, 0x0002, 0x1158, 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, + 0x2d00, 0x70be, 0x0038, 0x080c, 0x3d52, 0x0020, 0x7000, 0xa086, + 0x0003, 0x0dc8, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, + 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x89c0, 0xb284, + 0x0600, 0x1118, 0xc2fd, 0x2069, 0x8ad0, 0x2d04, 0x2d08, 0x715e, + 0xa06d, 0x0128, 0x6814, 0xa206, 0x0500, 0x6800, 0x0cb8, 0x7003, + 0x0005, 0xd2fc, 0x1118, 0x2001, 0x8ae0, 0x0010, 0x2001, 0x8b12, + 0x2068, 0x704e, 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, + 0x1f04, 0x347d, 0x015e, 0xad80, 0x0009, 0x7046, 0x6a16, 0x68b7, + 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6920, + 0xa184, 0x0c00, 0x0904, 0x3507, 0x681b, 0x0005, 0xc1ad, 0xc1d4, + 0x6922, 0x080c, 0x383d, 0x0804, 0x3507, 0x7200, 0xa286, 0x0002, + 0x1158, 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, + 0x0030, 0x080c, 0x3d52, 0x0018, 0xa286, 0x0003, 0x0dd0, 0x7003, + 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, + 0x001f, 0xa215, 0xb284, 0x0600, 0x1108, 0xc2fd, 0x79a8, 0x79a8, + 0xa18c, 0x00ff, 0x70cc, 0xa168, 0x2d04, 0x2d08, 0x715e, 0xa06d, + 0x0128, 0x6814, 0xa206, 0x0538, 0x6800, 0x0cb8, 0x7003, 0x0005, + 0xb284, 0x0600, 0x0118, 0x2001, 0x8ae0, 0x0010, 0x2001, 0x8b12, + 0x2068, 0x704e, 0x0156, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, + 0x1f04, 0x34dd, 0x015e, 0xb284, 0x0600, 0x0110, 0xc2fc, 0x0008, + 0xc2fd, 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, + 0x0800, 0x6827, 0x0003, 0x6eb4, 0x6920, 0xa184, 0x0c00, 0x0178, + 0xd0dc, 0x0118, 0x080c, 0x3843, 0x0050, 0x681b, 0x0005, 0xc1ad, + 0xc1d4, 0x6922, 0x080c, 0x383d, 0x707f, 0x0000, 0x0000, 0xa6ac, + 0x0060, 0x05c8, 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x11c0, + 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, 0xb7ff, 0xa586, 0x0060, + 0x0550, 0xc6ed, 0x7e5a, 0x2009, 0x0083, 0xd69c, 0x0128, 0x2009, + 0x0082, 0x2019, 0x0000, 0x2320, 0x791a, 0x080c, 0x3fb8, 0x0418, + 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x01a0, 0x7bd2, + 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xc6f4, 0x7e5a, 0x2011, 0x0083, + 0xd69c, 0x0128, 0x2011, 0x0082, 0x2019, 0x0000, 0x2320, 0x7a1a, + 0x080c, 0x3fe5, 0x0040, 0x7e5a, 0x2009, 0x0083, 0xd69c, 0x0110, + 0x2009, 0x0082, 0x791a, 0x68c0, 0x705a, 0x2d00, 0x704e, 0x68c4, + 0x2060, 0x71d4, 0xd1b4, 0x1904, 0x248c, 0x2300, 0xa405, 0x0904, + 0x248c, 0x70a4, 0xa086, 0x0001, 0x1904, 0x24ce, 0x0005, 0x6020, + 0xa005, 0x0150, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, + 0x700f, 0x0100, 0x702c, 0x6026, 0x0005, 0xa006, 0x080c, 0x3d52, + 0x682b, 0x0000, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040, + 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, 0x0002, 0x248f, 0x358b, + 0x3588, 0x35a7, 0x3594, 0x248f, 0x3586, 0x3586, 0x080c, 0x243b, + 0x0441, 0x0409, 0x0028, 0x0429, 0x705c, 0x2060, 0x6800, 0x6002, + 0x080c, 0x1d3d, 0x0804, 0x248f, 0x7064, 0x7067, 0x0000, 0x7083, + 0x0000, 0x0002, 0x35a3, 0x35a3, 0x35a2, 0x35a2, 0x35a2, 0x35a3, + 0x35a2, 0x35a3, 0x2971, 0x7067, 0x0000, 0x0804, 0x248f, 0x681b, + 0x0000, 0x0804, 0x3012, 0x6800, 0xa005, 0x1108, 0x6002, 0x6006, + 0x0005, 0x6410, 0x84ff, 0x0168, 0x2009, 0x4302, 0x2104, 0x8001, + 0x200a, 0x8421, 0x6412, 0x1128, 0x2021, 0x4304, 0x2404, 0xc0a5, + 0x2022, 0x6008, 0xc0a4, 0x600a, 0x0005, 0x6018, 0xa005, 0x0110, + 0x8001, 0x601a, 0x0005, 0x080c, 0x3aa0, 0x681b, 0x0018, 0x04a0, + 0x080c, 0x3aa0, 0x681b, 0x0019, 0x0478, 0x080c, 0x3aa0, 0x681b, + 0x001a, 0x0450, 0x080c, 0x3aa0, 0x681b, 0x0003, 0x0428, 0x7774, + 0x080c, 0x396d, 0x7178, 0xa18c, 0x00ff, 0x3210, 0xa294, 0x0600, + 0x0118, 0xa1e8, 0x88c0, 0x0010, 0xa1e8, 0x89d0, 0x2d04, 0x2d08, + 0x2068, 0xa005, 0x1118, 0x707e, 0x0804, 0x248f, 0x6814, 0xc0fc, + 0x7274, 0xc2fc, 0xa206, 0x0110, 0x6800, 0x0c88, 0x6800, 0x200a, + 0x681b, 0x0005, 0x707f, 0x0000, 0x080c, 0x35b1, 0x6820, 0xd084, + 0x1110, 0x080c, 0x35ab, 0x080c, 0x35c5, 0x681f, 0x0000, 0x6823, + 0x0020, 0x080c, 0x1d3d, 0x0804, 0x248f, 0xa282, 0x0003, 0x1904, + 0x380d, 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, + 0xc1bd, 0x6922, 0xd1c4, 0x0590, 0xc1c4, 0x6922, 0xa6b4, 0x00ff, + 0x0510, 0xa682, 0x001c, 0x0218, 0x0110, 0x2031, 0x001c, 0x852b, + 0x852b, 0x2041, 0x0000, 0x080c, 0x38c6, 0x0118, 0x080c, 0x36f6, + 0x00a0, 0x080c, 0x3892, 0x080c, 0x36f3, 0x6920, 0xc1c5, 0x6922, + 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, + 0x781b, 0x0082, 0x0005, 0x080c, 0x36f3, 0x7e58, 0xd6d4, 0x1118, + 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0x00c6, 0x7058, + 0x2060, 0x6100, 0xd1e4, 0x0578, 0x6208, 0x8217, 0xa294, 0x00ff, + 0xa282, 0x001c, 0x0218, 0x0110, 0x2011, 0x001c, 0x2600, 0xa202, + 0x1208, 0x2230, 0x6208, 0xa294, 0x00ff, 0x78ec, 0xd0e4, 0x0130, + 0xa282, 0x000a, 0x1240, 0x2011, 0x000a, 0x0028, 0xa282, 0x000c, + 0x1210, 0x2011, 0x000c, 0x2200, 0xa502, 0x1208, 0x2228, 0x080c, + 0x3896, 0x852b, 0x852b, 0x2041, 0x0000, 0x080c, 0x38c6, 0x0118, + 0x080c, 0x36f6, 0x0020, 0x080c, 0x3892, 0x080c, 0x36f3, 0x7858, + 0xc095, 0x785a, 0x00ce, 0x781b, 0x0082, 0x0005, 0x00c6, 0x2960, + 0x6000, 0xd0e4, 0x1178, 0x6010, 0xa084, 0x000f, 0x1130, 0x6104, + 0xa18c, 0xfff5, 0x6106, 0x00ce, 0x0005, 0x2011, 0x0032, 0x2019, + 0x0000, 0x00f0, 0x68a0, 0xd0cc, 0x1dc0, 0x6208, 0xa294, 0x00ff, + 0x78ec, 0xd0e4, 0x0130, 0xa282, 0x000b, 0x1218, 0x2011, 0x000a, + 0x0028, 0xa282, 0x000c, 0x1210, 0x2011, 0x000c, 0x6308, 0x831f, + 0xa39c, 0x00ff, 0xa382, 0x001c, 0x0218, 0x0110, 0x2019, 0x001c, + 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, + 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, 0x080c, 0x3850, 0x00ce, + 0x0005, 0x00c6, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x2011, + 0x0032, 0x2019, 0x0000, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0003, + 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, + 0x6822, 0x00ce, 0x0005, 0xa006, 0x2030, 0x2010, 0x00c6, 0x7158, + 0x2160, 0x2018, 0x2008, 0xa084, 0xffe0, 0xa635, 0x7e86, 0x6018, + 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084, 0x7770, 0xa18c, 0x000f, + 0xa105, 0x2029, 0x4305, 0x252c, 0xd5cc, 0x0140, 0xd3a4, 0x0110, + 0xa085, 0x0800, 0xd3fc, 0x0110, 0xa085, 0x8080, 0x78a6, 0x6016, + 0x788a, 0xa6b4, 0x001f, 0x8637, 0x8204, 0x8004, 0xa605, 0x600e, + 0x6004, 0xa084, 0xffd5, 0x6006, 0x00ce, 0x0005, 0xa282, 0x0002, + 0x1904, 0x3816, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc, 0x0568, + 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x1a04, 0x3809, + 0x080c, 0x379c, 0x080c, 0x36f3, 0xa980, 0x0001, 0x200c, 0x080c, + 0x3969, 0x080c, 0x3696, 0x88ff, 0x0178, 0x789b, 0x0060, 0x2800, + 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, + 0x0005, 0x781b, 0x0082, 0x0005, 0x7e58, 0xd6d4, 0x1118, 0x781b, + 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0xa282, 0x0002, 0x1218, + 0xa284, 0x0001, 0x0140, 0x7158, 0xa188, 0x0000, 0x210c, 0xd1ec, + 0x1110, 0x2011, 0x0000, 0x080c, 0x3883, 0x0471, 0x080c, 0x36f3, + 0x7858, 0xc095, 0x785a, 0x781b, 0x0082, 0x0005, 0x00c6, 0x0026, + 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x1150, 0x6014, 0xa084, + 0x0040, 0x1120, 0xc1a4, 0x6106, 0xa006, 0x0088, 0x2011, 0x0000, + 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, + 0x0004, 0x080c, 0x3850, 0x6820, 0xa085, 0x0200, 0x6822, 0x002e, + 0x00ce, 0x0005, 0x8807, 0xa715, 0x00c6, 0x2009, 0x0000, 0x7058, + 0x2060, 0x82ff, 0x0110, 0x2009, 0x0040, 0x6018, 0xa080, 0x0002, + 0x789a, 0x78a4, 0xa084, 0xff9f, 0xa105, 0xc0ec, 0xd0b4, 0x1108, + 0xc0ed, 0x6100, 0xd1f4, 0x0110, 0xa085, 0x0020, 0x78a6, 0x6016, + 0x788a, 0x6004, 0xa084, 0xffef, 0x6006, 0x00ce, 0x0005, 0x0006, + 0x7000, 0xa086, 0x0003, 0x0110, 0x000e, 0x0010, 0x000e, 0x0488, + 0xd6ac, 0x0578, 0x7888, 0xa084, 0x0040, 0x0558, 0x7bb8, 0x8307, + 0xa084, 0x007f, 0x1508, 0x8207, 0xa084, 0x00ff, 0xa09e, 0x0001, + 0x1904, 0x382d, 0xd6f4, 0x11d0, 0x79d8, 0x7adc, 0xa108, 0xa291, + 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x080c, 0x4083, 0x781b, + 0x0080, 0xb284, 0x0600, 0x0118, 0x2001, 0x0000, 0x0010, 0x2001, + 0x0001, 0x080c, 0x3f50, 0x0005, 0x080c, 0x243b, 0x781b, 0x0080, + 0x0005, 0x781b, 0x0083, 0x0005, 0x2039, 0x0000, 0x2041, 0x0000, + 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x36f6, 0x080c, 0x379a, + 0x7e58, 0x04f9, 0x781b, 0x0082, 0x0005, 0x0cd9, 0x6820, 0xc0c4, + 0x6822, 0x00c6, 0x7058, 0x2060, 0x0804, 0x3720, 0x0c91, 0x6820, + 0xc0cc, 0x6822, 0x00c6, 0x7058, 0x2060, 0x0804, 0x37b9, 0x0c49, + 0x6820, 0xa084, 0xecff, 0x6822, 0x00c6, 0x7058, 0x2060, 0x6004, + 0xa084, 0xffc5, 0x6006, 0x00ce, 0x0005, 0x0049, 0x781b, 0x0082, + 0x0005, 0x6827, 0x0002, 0x0049, 0x781b, 0x0082, 0x0005, 0x2001, + 0x0005, 0x0088, 0x2001, 0x000c, 0x0070, 0x6820, 0xc0d5, 0x6822, + 0x2001, 0x0006, 0x0040, 0x2001, 0x000d, 0x0028, 0x2001, 0x0009, + 0x0010, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, 0x7e5a, + 0x70d4, 0xd0b4, 0x0168, 0xc0b4, 0x70d6, 0x00c6, 0x70b8, 0xa065, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, + 0x0005, 0x0076, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, + 0xb28c, 0x0600, 0x0118, 0xa0e0, 0x47c0, 0x0010, 0xa0e0, 0x4840, + 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x7fe0, 0x78ae, 0x6012, + 0x79a4, 0xa184, 0x773f, 0x78a6, 0x6016, 0x6004, 0xa085, 0x0038, + 0x6006, 0x007e, 0x0005, 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, + 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004, + 0x0804, 0x3850, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, 0x0080, + 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa, + 0x789b, 0x0060, 0x78ab, 0x0005, 0x0804, 0x3850, 0x0156, 0x8007, + 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, + 0xa18c, 0xffe0, 0x2021, 0x3952, 0x2019, 0x0011, 0x20a9, 0x000e, + 0x2011, 0x0032, 0x2404, 0xa084, 0xffe0, 0xa106, 0x0128, 0x8420, + 0x2300, 0xa210, 0x1f04, 0x38ba, 0x015e, 0x0005, 0x0156, 0x0804, + 0x3908, 0x2021, 0x3960, 0x20a9, 0x0009, 0x2011, 0x0029, 0xa582, + 0x0028, 0x0550, 0x8420, 0x95a9, 0x2011, 0x0033, 0xa582, 0x0033, + 0x0618, 0x8420, 0x95a9, 0x2019, 0x000a, 0x2011, 0x0065, 0x2200, + 0xa502, 0x02d0, 0x8420, 0x2300, 0xa210, 0x1f04, 0x38df, 0x015e, + 0x0088, 0x2021, 0x3952, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, + 0x0033, 0x2200, 0xa502, 0x0240, 0x8420, 0x2300, 0xa210, 0x1f04, + 0x38f1, 0x015e, 0xa006, 0x0005, 0x8211, 0x015e, 0xa582, 0x0064, + 0x1220, 0x7808, 0xa085, 0x0070, 0x780a, 0x2404, 0xa005, 0x0005, + 0xa886, 0x0002, 0x01e8, 0x2021, 0x393e, 0x20a9, 0x000d, 0x2011, + 0x0028, 0xa582, 0x0028, 0x0d48, 0x8420, 0x2019, 0x0019, 0x2011, + 0x0033, 0x2200, 0xa502, 0x0e00, 0x8420, 0x2300, 0xa210, 0x1f04, + 0x3919, 0x015e, 0x2011, 0x0184, 0xa582, 0x0185, 0x0ab0, 0x0890, + 0x2021, 0x394d, 0x20a9, 0x0003, 0x2011, 0x0024, 0xa586, 0x0024, + 0x0960, 0x8420, 0x2011, 0x0028, 0xa586, 0x0028, 0x0930, 0x8420, + 0x2019, 0x0019, 0x2011, 0x0033, 0x0804, 0x38f1, 0x1021, 0x2202, + 0x3403, 0x4604, 0x5805, 0x6a06, 0x7c07, 0x4610, 0x4612, 0x5812, + 0x5a12, 0x6a14, 0x6c14, 0x6e14, 0x7e17, 0x9021, 0xb002, 0xe204, + 0xe210, 0xe210, 0x1209, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404, + 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07, 0x0e07, + 0x10e1, 0x330a, 0x5805, 0x5a05, 0x6a06, 0x6c06, 0x7c07, 0x7e07, + 0x0e00, 0x789b, 0x0080, 0xa046, 0x0005, 0xa784, 0x0f00, 0x800b, + 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xd7fc, + 0x0118, 0xa0e0, 0x68c0, 0x0010, 0xa0e0, 0x48c0, 0x0005, 0x00e6, + 0x00f6, 0xd084, 0x0138, 0x2079, 0x0100, 0x2009, 0x4380, 0x2071, + 0x4380, 0x0030, 0x2009, 0x4340, 0x2079, 0x0200, 0x2071, 0x4340, + 0x2091, 0x8000, 0x2104, 0xa084, 0x000f, 0x0002, 0x39c5, 0x39a0, + 0x39a0, 0x39a0, 0x39a0, 0x39a0, 0x399e, 0x399e, 0x080c, 0x243b, + 0x784b, 0x0004, 0x7848, 0xa084, 0x0004, 0x1de0, 0x784b, 0x0008, + 0x7848, 0xa084, 0x0008, 0x1de0, 0x68b4, 0xc0f5, 0x68b6, 0x7858, + 0xc0f5, 0x785a, 0x7830, 0xd0bc, 0x1180, 0xb284, 0x0800, 0x0118, + 0x0104, 0x39c5, 0x0010, 0x0304, 0x39c5, 0x681c, 0xd0ac, 0x1118, + 0x080c, 0x3a4b, 0x0010, 0x781b, 0x00fb, 0x2091, 0x8001, 0x00fe, + 0x00ee, 0x0005, 0x00c6, 0x2001, 0x4301, 0x2004, 0xd0ac, 0x1904, + 0x3a3d, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xb28c, 0x0600, 0x0118, 0xa0e0, 0x47c0, 0x0010, 0xa0e0, 0x4840, + 0x6004, 0xa084, 0x000a, 0x1904, 0x3a3d, 0x6108, 0xa194, 0xff00, + 0x0904, 0x3a3d, 0xa18c, 0x00ff, 0x601c, 0xa084, 0xff00, 0x0180, + 0x2001, 0x0009, 0xa102, 0x16b8, 0x2001, 0x000a, 0xa102, 0x16b0, + 0x2001, 0x000c, 0xa102, 0x16a8, 0x601c, 0xa084, 0x00ff, 0x601e, + 0x2001, 0x000a, 0xa106, 0x01a8, 0x2001, 0x000c, 0xa106, 0x01a0, + 0x2001, 0x0012, 0xa106, 0x0198, 0x2001, 0x0014, 0xa106, 0x0190, + 0x2001, 0x0019, 0xa106, 0x0188, 0x2001, 0x0032, 0xa106, 0x0180, + 0x00d8, 0x2009, 0x000c, 0x00d0, 0x2009, 0x0012, 0x00b8, 0x2009, + 0x0014, 0x00a0, 0x2009, 0x0019, 0x0088, 0x2009, 0x0020, 0x0070, + 0x2009, 0x003f, 0x0058, 0x2009, 0x000a, 0x0040, 0x2009, 0x000c, + 0x0028, 0x2009, 0x0019, 0x0010, 0x2011, 0x0000, 0x2100, 0xa205, + 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x00ce, 0x0005, 0x781b, + 0x0083, 0x0005, 0x781b, 0x0082, 0x0005, 0x781b, 0x0071, 0x0005, + 0x781b, 0x006e, 0x0005, 0x2009, 0x4319, 0x210c, 0xa186, 0x0000, + 0x0150, 0xa186, 0x0001, 0x0150, 0x701f, 0x000b, 0x7067, 0x0001, + 0x781b, 0x0054, 0x0005, 0x781b, 0x00f3, 0x0005, 0x701f, 0x000a, + 0x0005, 0x2009, 0x4319, 0x210c, 0xa186, 0x0000, 0x0168, 0xa186, + 0x0001, 0x0138, 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, 0x0054, + 0x0005, 0x701f, 0x000a, 0x0005, 0x781b, 0x00f2, 0x0005, 0x781b, + 0x00fb, 0x0005, 0x781b, 0x00fa, 0x0005, 0x781b, 0x00cc, 0x0005, + 0x781b, 0x00cb, 0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, + 0x7067, 0x0001, 0x781b, 0x0054, 0x0005, 0x7830, 0xa084, 0x00c0, + 0x1170, 0x7808, 0xc08c, 0x780a, 0xe000, 0xe000, 0xe000, 0xe000, + 0x78ec, 0xa084, 0x0021, 0x0118, 0x7808, 0xc08d, 0x780a, 0x0005, + 0x7808, 0xc08d, 0x780a, 0x0005, 0x7830, 0xa084, 0x0040, 0x1de0, + 0xb284, 0x0800, 0x0118, 0x1104, 0x3ab2, 0x0010, 0x1304, 0x3ab2, + 0x78ac, 0x0005, 0x7808, 0xa084, 0xfffd, 0x780a, 0xe000, 0xe000, + 0xe000, 0xe000, 0x78ec, 0xa084, 0x0021, 0x0140, 0xb284, 0x0800, + 0x0118, 0x1104, 0x3ac1, 0x0010, 0x1304, 0x3ac4, 0x78ac, 0x0006, + 0x7808, 0xa085, 0x0002, 0x780a, 0x000e, 0x0005, 0xa784, 0x0001, + 0x1904, 0x30a0, 0xa784, 0x0070, 0x0140, 0x00c6, 0x2d60, 0x2f68, + 0x080c, 0x23e1, 0x2d78, 0x2c68, 0x00ce, 0xa784, 0x0008, 0x0148, + 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, 0x248f, 0x0804, + 0x3a3f, 0xa784, 0x0004, 0x01c8, 0x78b8, 0xa084, 0x8000, 0x01a8, + 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, 0x248f, 0x78e4, + 0xa084, 0x0007, 0xa086, 0x0001, 0x1140, 0x78c0, 0xa685, 0x4800, + 0x2030, 0x7e5a, 0x781b, 0x00fb, 0x0005, 0xa784, 0x0080, 0x0140, + 0x7884, 0xd0fc, 0x0128, 0x080c, 0x382d, 0x681b, 0x0022, 0x0005, + 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, + 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, + 0x2a7a, 0xb284, 0x0800, 0x0110, 0x0104, 0x248c, 0x0304, 0x248c, + 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, + 0x0118, 0xa080, 0x4840, 0x0010, 0xa080, 0x47c0, 0x2060, 0x2048, + 0x705a, 0x2a60, 0x0005, 0x00c6, 0x2960, 0x6000, 0xd0ac, 0x0904, + 0x3b81, 0xd1ac, 0x05e0, 0x6108, 0x8117, 0xa18c, 0x00ff, 0x631c, + 0x832f, 0x68a0, 0xd0cc, 0x11c8, 0xa584, 0x00ff, 0x0138, 0x78ec, + 0xd0e4, 0x0110, 0x8213, 0x00b8, 0x2029, 0x0000, 0xa182, 0x000c, + 0x1290, 0x78ec, 0xd0e4, 0x1118, 0x2009, 0x000c, 0x0060, 0xa182, + 0x000b, 0x1248, 0x2009, 0x000a, 0x0030, 0x2009, 0x0032, 0x2011, + 0x0000, 0x2029, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, + 0x0004, 0x79aa, 0x78ab, 0x0000, 0x7aaa, 0x7baa, 0x7daa, 0xa8c0, + 0x0008, 0x6820, 0xa085, 0x1000, 0x6822, 0x080c, 0x3850, 0xa085, + 0x0001, 0x00ce, 0x0005, 0xa282, 0x0006, 0x1904, 0x381f, 0x7da8, + 0x7eac, 0x8637, 0xa5ac, 0x00ff, 0xa6b4, 0x00ff, 0x7fac, 0x8747, + 0xa7bc, 0x00ff, 0xa8c4, 0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1e4, + 0x05c8, 0xa18c, 0xecff, 0x6922, 0xa782, 0x0002, 0x1a04, 0x37fc, + 0xa6b4, 0x00ff, 0x0560, 0xa682, 0x0039, 0x1a04, 0x37fc, 0xa582, + 0x0009, 0x0a04, 0x37fc, 0xa882, 0x0003, 0x1a04, 0x37fc, 0xa886, + 0x0002, 0x0128, 0xa886, 0x0000, 0x0138, 0x0804, 0x37fc, 0xa786, + 0x0000, 0x0904, 0x37fc, 0x8634, 0x852b, 0x852b, 0x080c, 0x38c6, + 0x0904, 0x37fc, 0x080c, 0x36f6, 0x080c, 0x379a, 0x7e58, 0xd6d4, + 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0x080c, + 0x36f3, 0x0c90, 0xa886, 0x0002, 0x1108, 0x8634, 0x7158, 0xa188, + 0x0000, 0x210c, 0xd1ac, 0x0904, 0x37fc, 0xd1ec, 0x1120, 0x2039, + 0x0000, 0x2041, 0x0000, 0xd1e4, 0x1120, 0x2031, 0x0000, 0x2041, + 0x0000, 0xa782, 0x0002, 0x12c8, 0x621c, 0xa284, 0x00ff, 0xa706, + 0x0110, 0x2039, 0x0000, 0xa605, 0x0190, 0x6108, 0x811f, 0xa39c, + 0x00ff, 0x0168, 0xa302, 0x1208, 0x2330, 0x8807, 0xa705, 0xa086, + 0x0201, 0x0160, 0xa886, 0x0000, 0x0168, 0x2039, 0x0000, 0x2041, + 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, 0x0070, 0xa284, 0xff00, + 0x1108, 0x2040, 0xa184, 0x00ff, 0xa502, 0x0108, 0x2128, 0x852b, + 0x852b, 0x080c, 0x38c6, 0x0d58, 0x080c, 0x36f6, 0x080c, 0x379a, + 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, 0x0004, + 0x78ab, 0x0000, 0x7daa, 0x7eaa, 0x7faa, 0x2800, 0x78aa, 0x789b, + 0x0060, 0x78ab, 0x0005, 0x080c, 0x3850, 0x7858, 0xc095, 0x785a, + 0x781b, 0x0082, 0x0005, 0x0020, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, 0x0009, 0x0014, + 0x0014, 0x9855, 0x984d, 0x0014, 0x9911, 0x98ff, 0x0014, 0x0014, + 0x0090, 0x00e7, 0x0100, 0x0402, 0x2008, 0xf880, 0x0018, 0x0017, + 0x840f, 0xd8c1, 0x0014, 0x0016, 0xa20a, 0x0014, 0x300b, 0xa20c, + 0x0014, 0x2500, 0x0013, 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0xa200, 0x3806, 0x8839, 0x20c4, 0x0864, 0xa84f, + 0x3008, 0x28c1, 0x9d18, 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, + 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2, 0x9cce, 0xa8f3, + 0x0864, 0xa83d, 0x300c, 0xa801, 0x3008, 0x28e1, 0x9cce, 0x2021, + 0xa818, 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, 0x6fc0, 0x67a4, + 0x6c80, 0x0212, 0xa205, 0x883d, 0x882b, 0x1814, 0x883b, 0x7027, + 0x85f2, 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa814, 0x883e, + 0xa812, 0x280a, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x1814, + 0x883b, 0x7027, 0x8576, 0x8677, 0xa806, 0x796d, 0xa8da, 0x796b, + 0xa8f1, 0x7861, 0x883e, 0x206b, 0x28c1, 0x9d18, 0x2044, 0x2103, + 0x20b4, 0x2095, 0xa8ca, 0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, + 0x8000, 0x85a4, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, + 0x856e, 0x866f, 0x7121, 0x0014, 0x0704, 0x3008, 0x9cce, 0x0014, + 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, 0x856e, + 0x883f, 0x08e6, 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014, 0xf881, + 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, + 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0x3008, + 0x8000, 0x2849, 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2081, + 0x2802, 0x1011, 0xa8fc, 0xa889, 0x3008, 0x20a1, 0x283c, 0x1011, + 0xa8fc, 0xa209, 0x0017, 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, + 0x0014, 0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, + 0x26e0, 0x18f2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, + 0x9d22, 0x0704, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, + 0x0016, 0x6042, 0x8008, 0xa8fa, 0x8160, 0x842a, 0x8180, 0xf021, + 0x3008, 0x84a8, 0x11d7, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822, + 0x0016, 0x0000, 0x0126, 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, + 0x7204, 0x7008, 0xc09c, 0xa205, 0x1178, 0x720c, 0x82ff, 0x0128, + 0x8aff, 0x1150, 0x7200, 0xd284, 0x1138, 0x7007, 0x0004, 0x7003, + 0x0008, 0x012e, 0x2000, 0x0005, 0x7000, 0xa084, 0x0003, 0x7002, + 0xc69c, 0xd084, 0x05b8, 0x2001, 0x4301, 0x2004, 0xd0b4, 0x0904, + 0x3dcf, 0x7108, 0xe000, 0x7008, 0xa106, 0x1dd8, 0xa184, 0x0003, + 0x0904, 0x3dcf, 0xa184, 0x01e0, 0x1904, 0x3dcf, 0xd1f4, 0x1d88, + 0xa184, 0x3000, 0xa086, 0x1000, 0x0d60, 0x2011, 0x0180, 0x710c, + 0x8211, 0x0130, 0x7008, 0xd0f4, 0x1d20, 0x700c, 0xa106, 0x0dc0, + 0x7007, 0x0012, 0x7108, 0xe000, 0x7008, 0xa106, 0x1dd8, 0xa184, + 0x0003, 0x0568, 0xd194, 0x0db0, 0xd1f4, 0x0548, 0x7007, 0x0002, + 0x0880, 0x0428, 0x7108, 0xd1fc, 0x0130, 0x080c, 0x3e9e, 0x8aff, + 0x0904, 0x3d58, 0x0cb8, 0x700c, 0xa08c, 0x07ff, 0x01e8, 0x7004, + 0xd084, 0x0178, 0x7014, 0xa005, 0x1148, 0x7010, 0x7310, 0xa306, + 0x1de0, 0x2300, 0xa005, 0x0128, 0xa102, 0x1e20, 0x7007, 0x0010, + 0x0030, 0x8aff, 0x0148, 0x080c, 0x4046, 0x1de8, 0x09d8, 0x080c, + 0x3e58, 0x012e, 0x2000, 0x0005, 0x7204, 0x7108, 0xc19c, 0x8103, + 0x1218, 0x080c, 0x3e9e, 0x0cc0, 0xa205, 0x1d88, 0x7007, 0x0004, + 0x7003, 0x0008, 0x012e, 0x2000, 0x0005, 0x6428, 0x84ff, 0x0508, + 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x3e19, 0x273c, 0x87fb, + 0x1148, 0x0210, 0x080c, 0x243b, 0x609c, 0xa075, 0x0190, 0x0c88, + 0x2039, 0x3e0e, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529, + 0x8421, 0x0138, 0x8738, 0x2704, 0xa005, 0x1da8, 0x709c, 0xa075, + 0x1d00, 0x0005, 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, 0x0015, + 0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, + 0x0000, 0x0000, 0x3e0e, 0x3e0b, 0x0000, 0x0000, 0x8000, 0x0000, + 0x3e0e, 0x0000, 0x3e16, 0x3e13, 0x0000, 0x0000, 0x0000, 0x0000, + 0x3e16, 0x0000, 0x3e11, 0x3e11, 0x0000, 0x0000, 0x8000, 0x0000, + 0x3e11, 0x0000, 0x3e17, 0x3e17, 0x0000, 0x0000, 0x0000, 0x0000, + 0x3e17, 0x2079, 0x4300, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, + 0x0002, 0x7003, 0x0001, 0x2009, 0x0002, 0x2071, 0x0050, 0x7007, + 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2001, 0x01ff, 0x2004, + 0xd0fc, 0x1128, 0x8109, 0x0118, 0x2071, 0x0020, 0x0c80, 0x0005, + 0x7004, 0x8004, 0x1690, 0x7007, 0x0012, 0x2019, 0x0000, 0x7108, + 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0110, 0x080c, 0x243b, + 0xa19c, 0x300c, 0xa386, 0x2004, 0x0130, 0xa386, 0x0008, 0x0160, + 0xa386, 0x200c, 0x1d60, 0x7200, 0x8204, 0x0230, 0x730c, 0xa384, + 0x07ff, 0x0110, 0x080c, 0x243b, 0x7007, 0x0012, 0x7000, 0xd084, + 0x1160, 0x7008, 0xa084, 0x01e0, 0x1140, 0x7310, 0x7014, 0xa305, + 0x0120, 0x710c, 0xa184, 0x07ff, 0x1958, 0x7007, 0x0012, 0x7007, + 0x0008, 0x7004, 0xd09c, 0x1de8, 0x7007, 0x0012, 0x7108, 0x8103, + 0x0ed8, 0x7003, 0x0008, 0x0005, 0x7108, 0x0000, 0xa184, 0x01e0, + 0x1550, 0x7108, 0xa184, 0x01e0, 0x1530, 0xa184, 0x0007, 0x0002, + 0x3eb2, 0x3ec0, 0x3eb0, 0x3ec0, 0x3eb0, 0x3f06, 0x3eb0, 0x3f05, + 0x080c, 0x243b, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, + 0x1118, 0x2049, 0x0000, 0x0005, 0x080c, 0x4046, 0x1de8, 0x0005, + 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x0118, 0x080c, + 0x4046, 0x1de8, 0x0005, 0x7007, 0x0012, 0x7108, 0x1d04, 0x3ece, + 0x2091, 0x6000, 0x1d04, 0x3ed2, 0x2091, 0x6000, 0x7007, 0x0012, + 0x7007, 0x0008, 0x7004, 0xd09c, 0x1de8, 0x7007, 0x0012, 0x7108, + 0xd1fc, 0x1dd8, 0x7003, 0x0000, 0x7000, 0xa005, 0x1130, 0x7004, + 0xa005, 0x1118, 0x700c, 0xa005, 0x0108, 0x0c40, 0x2049, 0x0000, + 0xb284, 0x0200, 0x0118, 0x2001, 0x0000, 0x0010, 0x2001, 0x0001, + 0x080c, 0x397f, 0x6818, 0xa084, 0x8000, 0x0110, 0x681b, 0x0002, + 0x0005, 0x080c, 0x243b, 0x080c, 0x243b, 0x04b9, 0x7210, 0x7114, + 0x700c, 0xa09c, 0x07ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, + 0x0461, 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, + 0x2100, 0xa31b, 0x2400, 0xa305, 0x0140, 0x1238, 0x8412, 0x8210, + 0x830a, 0xa189, 0x0000, 0x2b60, 0x0c58, 0x2b60, 0x8a07, 0x0006, + 0x6004, 0xa084, 0x0008, 0x0118, 0xa7ba, 0x3e13, 0x0010, 0xa7ba, + 0x3e0b, 0x000e, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, 0x6b8e, + 0x7007, 0x0012, 0x080c, 0x3e58, 0x0005, 0x8a50, 0x8739, 0x2704, + 0xa004, 0x1168, 0x6000, 0xa064, 0x1108, 0x2d60, 0x6004, 0xa084, + 0x000f, 0xa080, 0x3e29, 0x203c, 0x87fb, 0x090c, 0x243b, 0x0005, + 0x0126, 0x00d6, 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, + 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, + 0xa084, 0x00ff, 0x0006, 0x6804, 0xa084, 0x0008, 0x000e, 0x0118, + 0xa0b8, 0x3e13, 0x0010, 0xa0b8, 0x3e0b, 0xb284, 0x0200, 0x0110, + 0x7e20, 0x0008, 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0108, + 0xc685, 0x2400, 0xa305, 0x0520, 0x2c58, 0x2704, 0x6104, 0xac60, + 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, 0x0008, + 0x0140, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, 0xa081, 0x0000, + 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, + 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x080c, 0x4067, 0x0010, + 0x080c, 0x4046, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x00d6, + 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x7007, 0x0004, + 0x7004, 0xd094, 0x1de8, 0x7003, 0x0008, 0x012e, 0x2000, 0x0005, + 0x0126, 0x00d6, 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, + 0x7e20, 0xb284, 0x0200, 0x1108, 0x7e24, 0xa6b5, 0x000c, 0x681c, + 0xd0ac, 0x1118, 0xc685, 0x7003, 0x0000, 0x6828, 0x2050, 0x2d60, + 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x3e19, 0x273c, 0x87fb, 0x1138, + 0x0210, 0x080c, 0x243b, 0x689c, 0xa065, 0x0120, 0x0c88, 0x080c, + 0x4046, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x0006, 0x0016, + 0x00d6, 0x70d4, 0xa084, 0x4c00, 0x8004, 0x2090, 0x7e20, 0xb284, + 0x0200, 0x1108, 0x7e24, 0x00de, 0x003e, 0x004e, 0xa6b5, 0x000c, + 0x681c, 0xd0b4, 0x0128, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, + 0x2049, 0x3fe5, 0x6828, 0xa055, 0x05f0, 0x2d70, 0x2e60, 0x7004, + 0xa0bc, 0x000f, 0xa7b8, 0x3e19, 0x273c, 0x87fb, 0x1140, 0x0210, + 0x080c, 0x243b, 0x709c, 0xa075, 0x2060, 0x0568, 0x0c80, 0x2704, + 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0268, 0x8a51, 0x1110, + 0x080c, 0x243b, 0x8738, 0x2704, 0xa005, 0x1d90, 0x709c, 0xa075, + 0x2060, 0x01c8, 0x08e0, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, + 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x1210, 0x080c, + 0x243b, 0xb284, 0x0200, 0x0118, 0x2071, 0x0050, 0x0010, 0x2071, + 0x0020, 0x0804, 0x3f79, 0x012e, 0x2000, 0x0005, 0x7008, 0xa084, + 0x0003, 0xa086, 0x0003, 0x1108, 0x0005, 0x2704, 0xac78, 0x7800, + 0x701a, 0x7804, 0x701e, 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, + 0xa084, 0x0008, 0x0120, 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, + 0x7004, 0xa084, 0x0010, 0xc085, 0x7006, 0x2079, 0x4300, 0x8a51, + 0x01b0, 0x8738, 0x2704, 0xa005, 0x1168, 0x609c, 0xa005, 0x0180, + 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x3e19, 0x203c, 0x87fb, + 0x090c, 0x243b, 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, 0x0005, + 0x2051, 0x0000, 0x0005, 0x0126, 0x0006, 0x00d6, 0x70d4, 0xa084, + 0x4c00, 0x8004, 0x2090, 0x00de, 0x008e, 0x7108, 0xa184, 0x0003, + 0x1128, 0x6828, 0xa005, 0x0178, 0x0804, 0x3d6c, 0x7108, 0xd1fc, + 0x0118, 0x080c, 0x3e9e, 0x0c88, 0x7007, 0x0010, 0x7108, 0xd1fc, + 0x0de8, 0x080c, 0x3e9e, 0x7008, 0xa086, 0x0008, 0x1d30, 0x7000, + 0xa005, 0x1d18, 0x7003, 0x0000, 0x2049, 0x0000, 0x012e, 0x2000, + 0x0005, 0x0126, 0x0146, 0x0136, 0x0156, 0x00c6, 0x00d6, 0x70d4, + 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x2049, 0x40b1, 0xad80, + 0x0011, 0x20a0, 0xb284, 0x0200, 0x0118, 0x2099, 0x0032, 0x0010, + 0x2099, 0x0031, 0x700c, 0xa084, 0x07ff, 0x682a, 0x7007, 0x0008, + 0x7007, 0x0002, 0x7003, 0x0001, 0x0118, 0x8000, 0x80ac, 0x53a5, + 0x700c, 0xa084, 0x07ff, 0x0130, 0x7007, 0x0004, 0x7004, 0xa084, + 0x0004, 0x1de0, 0x00ce, 0x2049, 0x0000, 0x7003, 0x0000, 0x015e, + 0x013e, 0x014e, 0x012e, 0x2000, 0x0005, 0x2091, 0x8000, 0x2091, + 0x6000, 0x78ac, 0xa005, 0x1168, 0x7974, 0x70d0, 0xa106, 0x1148, + 0x781c, 0xa005, 0x0130, 0x781f, 0x0000, 0x0e04, 0x4101, 0x2091, + 0x4080, 0x7830, 0x8001, 0x7832, 0x1904, 0x416b, 0x7834, 0x7832, + 0x2061, 0x68c0, 0x2069, 0x4380, 0xc7fd, 0x68d0, 0xa005, 0x0128, + 0x8001, 0x68d2, 0x1110, 0x080c, 0x42c4, 0x6800, 0xa084, 0x000f, + 0x0168, 0xa086, 0x0001, 0x0150, 0x6844, 0xa00d, 0x0138, 0x2104, + 0xa005, 0x0120, 0x8001, 0x200a, 0x0904, 0x425f, 0x6814, 0xa005, + 0x01a8, 0x8001, 0x6816, 0x1190, 0x68a7, 0x0001, 0x00f6, 0xd7fc, + 0x1118, 0x2079, 0x0200, 0x0010, 0x2079, 0x0100, 0x080c, 0x3aa0, + 0x00fe, 0x6864, 0xa005, 0x0110, 0x080c, 0x2233, 0x6880, 0xa005, + 0x0140, 0x8001, 0x6882, 0x1128, 0x6867, 0x0000, 0x68d4, 0xc0c5, + 0x68d6, 0x68d4, 0xd0fc, 0x01b0, 0xc0fc, 0x68d6, 0x20a9, 0x0200, + 0x6034, 0xa005, 0x0158, 0x8001, 0x6036, 0x68d4, 0xc0fd, 0x68d6, + 0x1128, 0x6010, 0xa005, 0x0110, 0x080c, 0x2233, 0xace0, 0x0010, + 0x1f04, 0x4150, 0xd7fc, 0x0138, 0x2061, 0x48c0, 0x2069, 0x4340, + 0xc7fc, 0x0804, 0x410d, 0x0459, 0x7838, 0x8001, 0x783a, 0x11a0, + 0x783c, 0x783a, 0x2061, 0x48c0, 0x2069, 0x4340, 0xc7fc, 0x680c, + 0xa005, 0x0110, 0x080c, 0x41c9, 0xd7fc, 0x1130, 0x2061, 0x68c0, + 0x2069, 0x4380, 0xc7fd, 0x0c98, 0x7810, 0xd0cc, 0x0168, 0xd0ac, + 0x1120, 0xd0a4, 0x0148, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0e04, + 0x4193, 0x080c, 0x1ffe, 0x0005, 0x2091, 0x8001, 0x0005, 0x7840, + 0x8001, 0x7842, 0x1568, 0x7844, 0x7842, 0x2091, 0x8000, 0x2061, + 0x48c0, 0x2069, 0x4340, 0xc7fc, 0x6810, 0xa005, 0x1110, 0x2001, + 0x0101, 0x8001, 0x6812, 0xd7fc, 0x0118, 0xa080, 0x89d0, 0x0010, + 0xa080, 0x88c0, 0x2040, 0x2004, 0xa065, 0x0150, 0x6024, 0xa005, + 0x0120, 0x8001, 0x6026, 0x0904, 0x4207, 0x6000, 0x2c40, 0x0ca0, + 0xd7fc, 0x1130, 0x2061, 0x68c0, 0x2069, 0x4380, 0xc7fd, 0x08e0, + 0x0005, 0x2009, 0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0540, + 0x6024, 0xa005, 0x0118, 0x8001, 0x6026, 0x0400, 0x6008, 0xc09c, + 0xd084, 0x1110, 0xd0ac, 0x01a8, 0x600a, 0x6004, 0xa06d, 0x01c0, + 0x00c6, 0x0016, 0x6010, 0x8001, 0x6012, 0x080c, 0x35ab, 0x2d00, + 0x2c68, 0x2060, 0x080c, 0x1b85, 0x080c, 0x1d30, 0x001e, 0x00ce, + 0x0038, 0xc0bd, 0x600a, 0xa18d, 0x0001, 0x0010, 0xa18d, 0x0100, + 0xace0, 0x0010, 0x1f04, 0x41cd, 0xa184, 0x0001, 0x0130, 0xa18c, + 0xfffe, 0x690e, 0x080c, 0x2233, 0x0008, 0x690e, 0x0005, 0x6800, + 0xa005, 0x0120, 0x684c, 0xac06, 0x0904, 0x425f, 0x6864, 0xa005, + 0x0120, 0x6027, 0x0001, 0x0804, 0x425c, 0x2c00, 0x687e, 0x6714, + 0x6f76, 0x6017, 0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x60b4, + 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, + 0x6022, 0x6000, 0x2042, 0x080c, 0x1b1d, 0x6818, 0xa005, 0x0110, + 0x8001, 0x681a, 0x6808, 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, + 0x790a, 0x8001, 0x1310, 0x080c, 0x243b, 0x6812, 0x1118, 0x7910, + 0xc1a5, 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x080c, + 0x1d3d, 0xd7fc, 0x1118, 0x2069, 0x4340, 0x0010, 0x2069, 0x4380, + 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x1118, 0x697a, 0x2001, + 0x0004, 0x2708, 0x080c, 0x2228, 0x2091, 0x8001, 0x0005, 0x00d6, + 0x694c, 0x2160, 0xd7fc, 0x1118, 0x2069, 0x0200, 0x0010, 0x2069, + 0x0100, 0x080c, 0x23e1, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, + 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, + 0x0000, 0x6033, 0x0000, 0x6830, 0xd0b4, 0x01b0, 0x684b, 0x0004, + 0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, 0x1f04, 0x4282, 0x684b, + 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0110, 0x1f04, 0x428b, + 0x20a9, 0x00fa, 0x1f04, 0x4292, 0x6808, 0xa084, 0xfffd, 0x680a, + 0x681b, 0x0054, 0x00de, 0x6867, 0x0007, 0x2091, 0x8001, 0x0005, + 0x2079, 0x4300, 0x00e1, 0x0089, 0x00a9, 0x2009, 0x0002, 0x2069, + 0x4380, 0x680f, 0x0000, 0x6813, 0x0000, 0x6817, 0x0000, 0x8109, + 0x0118, 0x2069, 0x4340, 0x0ca8, 0x0005, 0x2019, 0x00a3, 0x7b3a, + 0x7b3e, 0x0005, 0x2019, 0x0033, 0x7b42, 0x7b46, 0x0005, 0x2019, + 0x32dd, 0x7b32, 0x7b36, 0x0005, 0x6950, 0xa185, 0x0000, 0x0178, + 0x00c6, 0x6ac0, 0x2264, 0x602b, 0x0000, 0x602f, 0x0000, 0x6008, + 0xc0b5, 0x600a, 0x8210, 0x8109, 0x1da8, 0x6952, 0x00ce, 0x0005, + 0x70ec, 0xd0dc, 0x1118, 0xd0d4, 0x0180, 0x0088, 0xae8e, 0x0100, + 0x0130, 0x7814, 0xc0f5, 0x7816, 0xd0d4, 0x1170, 0x0050, 0x7814, + 0xc0fd, 0x7816, 0xd0d4, 0x1140, 0x0020, 0xd0e4, 0x0138, 0x70a0, + 0x70a2, 0x7804, 0xd08c, 0x0110, 0x681f, 0x000c, 0x0005, 0xaf67 +}; +#ifdef UNIQUE_FW_NAME +unsigned short fw12160i_length01 = 0x32f8; +#else +unsigned short risc_code_length01 = 0x32f8; +#endif + diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/ql1280_fw.h linux/drivers/scsi/ql1280_fw.h --- v2.3.42/linux/drivers/scsi/ql1280_fw.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/ql1280_fw.h Mon Feb 7 19:45:28 2000 @@ -0,0 +1,1898 @@ +/************************************************************************ + * * + * --- ISP1240/1080/1280 Initiator Firmware --- * + * 32 LUN Support * + * * + ************************************************************************ + * Copyright (C) 1999,2000 Qlogic, Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted provided + * that the following conditions are met: + * 1. Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. + * * + ************************************************************************ + */ + + +/* + * Firmware Version 8.09.00 (18:29 Apr 16, 1999) + */ + +unsigned short fw1280ei_version = 8*1024+9; + +unsigned char fw1280ei_version_str[] = {8,9,0}; + +unsigned short fw1280ei_addr01 = 0x1000 ; + +unsigned short fw1280ei_code01[] = { + 0x0078, 0x1041, 0x0000, 0x39e3, 0x0000, 0x2043, 0x4f50, 0x5952, + 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31, + 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320, + 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350, + 0x3132, 0x3430, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056, + 0x6572, 0x7369, 0x6f6e, 0x2030, 0x382e, 0x3039, 0x2020, 0x2043, + 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050, + 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020, + 0x2400, 0x20c9, 0x93ff, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1080, + 0x00c0, 0x1054, 0x2071, 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, + 0x2089, 0x136a, 0x0078, 0x106d, 0x2001, 0x04fc, 0x2004, 0xa086, + 0x1280, 0x00c0, 0x1069, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2071, + 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, 0x2089, 0x13ea, 0x0078, + 0x106d, 0x20c1, 0x0020, 0x2089, 0x1312, 0x2071, 0x0010, 0x70c3, + 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, + 0x0008, 0x2001, 0x04fe, 0x70d6, 0x20c1, 0x0021, 0x2019, 0x0000, + 0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, + 0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, + 0xa286, 0xa5a5, 0x0040, 0x10a4, 0xa386, 0x000f, 0x0040, 0x10a0, + 0x2c6a, 0x2a5a, 0x20c1, 0x0020, 0x2019, 0x000f, 0x0078, 0x1080, + 0x2c6a, 0x2a5a, 0x0078, 0x10a2, 0x2c6a, 0x2a5a, 0x2130, 0x2128, + 0xa1a2, 0x4a00, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, + 0xa192, 0x9400, 0x2009, 0x0000, 0x2001, 0x0032, 0x1078, 0x2078, + 0x2218, 0x2079, 0x4a00, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, + 0x0040, 0x42a4, 0x8109, 0x00c0, 0x10bf, 0x2001, 0x04fc, 0x2004, + 0xa086, 0x1080, 0x00c0, 0x10db, 0x2071, 0x0100, 0x0d7e, 0x2069, + 0x4a40, 0x1078, 0x49ae, 0x0d7f, 0x7810, 0xc0ed, 0x7812, 0x781b, + 0x0064, 0x0078, 0x1100, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1280, + 0x00c0, 0x10fb, 0x7814, 0xc0ed, 0xc0d5, 0x7816, 0x781b, 0x0064, + 0x2071, 0x0200, 0x0d7e, 0x2069, 0x4a40, 0x1078, 0x49ae, 0x2069, + 0x4a80, 0x2071, 0x0100, 0x1078, 0x49ae, 0x7814, 0xc0d4, 0x7816, + 0x0d7f, 0x0078, 0x1100, 0x7814, 0xc0e5, 0x7816, 0x781b, 0x003c, + 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, 0xc08d, 0x7802, + 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, 0x7827, 0x0002, + 0x2009, 0x0002, 0x2069, 0x4a40, 0x681b, 0x0003, 0x6823, 0x0007, + 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0000, + 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000, 0x8109, 0x0040, + 0x1154, 0x68d3, 0x000a, 0x68c3, 0x4ac0, 0x2079, 0x4a00, 0x7814, + 0xd0e4, 0x00c0, 0x113a, 0xd0ec, 0x00c0, 0x113e, 0x68d7, 0x7329, + 0x0078, 0x1140, 0x68d7, 0x730d, 0x0078, 0x1140, 0x68d7, 0x7329, + 0x68c7, 0x4fc0, 0x68cb, 0x4ec0, 0x68cf, 0x8fc0, 0x68ab, 0x9244, + 0x68af, 0x9249, 0x68b3, 0x9244, 0x68b7, 0x9244, 0x68a7, 0x0001, + 0x2069, 0x4a80, 0x0078, 0x1114, 0x68d3, 0x000a, 0x68c3, 0x4cc0, + 0x7814, 0xd0e4, 0x00c0, 0x1160, 0x68d7, 0x7439, 0x0078, 0x1162, + 0x68d7, 0x7419, 0x68c7, 0x6fc0, 0x68cb, 0x4f40, 0x68cf, 0x90d0, + 0x68ab, 0x9249, 0x68af, 0x924e, 0x68b3, 0x9249, 0x68b7, 0x9249, + 0x68a7, 0x0001, 0x7810, 0xd0ec, 0x00c0, 0x11b8, 0x7814, 0xd0e4, + 0x00c0, 0x11aa, 0x0e7e, 0x2069, 0x4ec0, 0x2071, 0x0200, 0x70ec, + 0xd0e4, 0x00c0, 0x118b, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, + 0x2007, 0x0078, 0x1191, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, + 0x2007, 0x2069, 0x4f40, 0x2071, 0x0100, 0x70ec, 0xd0e4, 0x00c0, + 0x11a1, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, 0x2007, 0x0078, + 0x11a7, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, 0x2007, 0x0e7f, + 0x0078, 0x11d1, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x2069, 0x4ec0, + 0x1078, 0x2007, 0x2069, 0x4f40, 0x1078, 0x2007, 0x0078, 0x11d1, + 0x2069, 0x4ec0, 0x0e7e, 0x2071, 0x0100, 0x70ec, 0xd0e4, 0x00c0, + 0x11ca, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078, 0x2007, 0x0e7f, + 0x0078, 0x11d1, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078, 0x2007, + 0x0e7f, 0x2011, 0x0002, 0x2069, 0x4fc0, 0x2009, 0x0002, 0x20a9, + 0x0100, 0x683f, 0x0000, 0x680b, 0x0040, 0x7bc8, 0xa386, 0xfeff, + 0x00c0, 0x11e8, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x11ec, + 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x00f0, 0x11d9, + 0x8109, 0x00c0, 0x11d7, 0x8211, 0x0040, 0x11fa, 0x2069, 0x6fc0, + 0x0078, 0x11d5, 0x1078, 0x2611, 0x1078, 0x441d, 0x1078, 0x1df2, + 0x1078, 0x4957, 0x2091, 0x2100, 0x2079, 0x4a00, 0x7810, 0xd0ec, + 0x0040, 0x120e, 0x2071, 0x0020, 0x0078, 0x1210, 0x2071, 0x0050, + 0x2091, 0x2200, 0x2079, 0x4a00, 0x2071, 0x0020, 0x2091, 0x2300, + 0x2079, 0x4a00, 0x7810, 0xd0ec, 0x0040, 0x1222, 0x2079, 0x0100, + 0x0078, 0x1224, 0x2079, 0x0200, 0x2071, 0x4a40, 0x2091, 0x2400, + 0x2079, 0x0100, 0x2071, 0x4a80, 0x2091, 0x2000, 0x2079, 0x4a00, + 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090, 0x2071, 0x0010, + 0x70c3, 0x0000, 0x0090, 0x1243, 0x70c0, 0xa086, 0x0002, 0x00c0, + 0x1243, 0x1078, 0x159d, 0x2039, 0x0000, 0x7810, 0xd0ec, 0x00c0, + 0x12c5, 0x1078, 0x1472, 0x78ac, 0xa005, 0x00c0, 0x1261, 0x0068, + 0x1257, 0x786c, 0xa065, 0x0040, 0x1257, 0x1078, 0x2368, 0x1078, + 0x209f, 0x0068, 0x126e, 0x786c, 0xa065, 0x0040, 0x1261, 0x1078, + 0x2368, 0x0068, 0x126e, 0x2009, 0x4a47, 0x2011, 0x4a87, 0x2104, + 0x220c, 0xa105, 0x0040, 0x126e, 0x1078, 0x1f1e, 0x2071, 0x4a40, + 0x70a4, 0xa005, 0x0040, 0x1293, 0x7450, 0xa485, 0x0000, 0x0040, + 0x1293, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4, 0xa28c, 0x303d, + 0x2190, 0x1078, 0x2a9c, 0x2091, 0x8000, 0x2091, 0x303d, 0x0068, + 0x1293, 0x2079, 0x4a00, 0x786c, 0xa065, 0x0040, 0x1293, 0x2071, + 0x0010, 0x1078, 0x2368, 0x00e0, 0x129b, 0x2079, 0x4a00, 0x2071, + 0x0010, 0x1078, 0x4765, 0x2071, 0x4a80, 0x70a4, 0xa005, 0x0040, + 0x12b3, 0x7050, 0xa025, 0x0040, 0x12b3, 0x2079, 0x0100, 0x2091, + 0x8000, 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, 0x2a9c, 0x2091, + 0x8000, 0x2091, 0x303d, 0x2079, 0x4a00, 0x2071, 0x0010, 0x0068, + 0x12bf, 0x786c, 0xa065, 0x0040, 0x12bf, 0x1078, 0x2368, 0x00e0, + 0x1249, 0x1078, 0x4765, 0x0078, 0x1249, 0x1078, 0x1472, 0x78ac, + 0xa005, 0x00c0, 0x12dd, 0x0068, 0x12d3, 0x786c, 0xa065, 0x0040, + 0x12d3, 0x1078, 0x2368, 0x1078, 0x209f, 0x0068, 0x12e7, 0x786c, + 0xa065, 0x0040, 0x12dd, 0x1078, 0x2368, 0x0068, 0x12e7, 0x2009, + 0x4a47, 0x2104, 0xa005, 0x0040, 0x12e7, 0x1078, 0x1f1e, 0x2071, + 0x4a40, 0x70a4, 0xa005, 0x0040, 0x1302, 0x7450, 0xa485, 0x0000, + 0x0040, 0x1302, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d4, 0xa28c, + 0x303d, 0x2190, 0x1078, 0x2a9c, 0x2091, 0x8000, 0x2091, 0x303d, + 0x2079, 0x4a00, 0x2071, 0x0010, 0x0068, 0x130c, 0x786c, 0xa065, + 0x0040, 0x130c, 0x1078, 0x2368, 0x00e0, 0x12c5, 0x1078, 0x4765, + 0x0078, 0x12c5, 0x1332, 0x1332, 0x1334, 0x1334, 0x1341, 0x1341, + 0x1341, 0x1341, 0x134c, 0x134c, 0x1359, 0x1359, 0x1341, 0x1341, + 0x1341, 0x1341, 0x1332, 0x1332, 0x1334, 0x1334, 0x1341, 0x1341, + 0x1341, 0x1341, 0x134c, 0x134c, 0x1359, 0x1359, 0x1341, 0x1341, + 0x1341, 0x1341, 0x0078, 0x1332, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13ba, 0x127f, 0x107f, + 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x290b, + 0x2091, 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, + 0x8001, 0x007c, 0x138a, 0x138a, 0x138c, 0x138c, 0x1399, 0x1399, + 0x1399, 0x1399, 0x13a4, 0x13a4, 0x138c, 0x138c, 0x1399, 0x1399, + 0x1399, 0x1399, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, + 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, 0x13a5, + 0x13a5, 0x13a5, 0x0078, 0x138a, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13c7, 0x127f, 0x107f, + 0x007f, 0x2091, 0x8001, 0x007c, 0x007c, 0x107e, 0x127e, 0x0d7e, + 0x0e7e, 0x0f7e, 0x007e, 0x2071, 0x0100, 0x2069, 0x4a40, 0x2079, + 0x4a00, 0x1078, 0x49ae, 0x007f, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, + 0x107f, 0x007c, 0x3c00, 0xa084, 0x0007, 0x0079, 0x13bf, 0x13d0, + 0x13d0, 0x13d2, 0x13d2, 0x13d7, 0x13d7, 0x13dc, 0x13dc, 0x3c00, + 0xa084, 0x0003, 0x0079, 0x13cc, 0x13d0, 0x13d0, 0x13e5, 0x13e5, + 0x1078, 0x28ec, 0x2091, 0x2200, 0x1078, 0x44b7, 0x007c, 0x2091, + 0x2100, 0x1078, 0x44b7, 0x007c, 0x2091, 0x2100, 0x1078, 0x44b7, + 0x2091, 0x2200, 0x1078, 0x44b7, 0x007c, 0x2091, 0x2100, 0x1078, + 0x44b7, 0x007c, 0x140a, 0x140a, 0x140c, 0x140c, 0x1419, 0x1419, + 0x1419, 0x1419, 0x1424, 0x1424, 0x1431, 0x1431, 0x1419, 0x1419, + 0x1419, 0x1419, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, + 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, 0x1442, + 0x1442, 0x1442, 0x0078, 0x140a, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13ba, 0x127f, 0x107f, + 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, + 0x2300, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, + 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x290b, + 0x2091, 0x2400, 0x1078, 0x290b, 0x127f, 0x107f, 0x007f, 0x2091, + 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, + 0x2079, 0x4a00, 0x2071, 0x0200, 0x2069, 0x4a40, 0x3d00, 0xd08c, + 0x00c0, 0x1456, 0x2069, 0x4a80, 0x2071, 0x0100, 0x1078, 0x49ae, + 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, 0x107f, 0x007f, 0x007c, 0x7008, + 0x800b, 0x00c8, 0x146d, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, + 0x146e, 0xd09c, 0x0040, 0x146d, 0x087a, 0x097a, 0x70c3, 0x4002, + 0x0078, 0x15a0, 0x0068, 0x14f7, 0x2061, 0x0000, 0x6018, 0xd084, + 0x00c0, 0x14f7, 0x7828, 0xa005, 0x00c0, 0x1482, 0x0010, 0x14f8, + 0x0078, 0x14f7, 0x7910, 0xd1f4, 0x0040, 0x148a, 0x2001, 0x4007, + 0x0078, 0x159f, 0x7914, 0xd1ec, 0x0040, 0x14a5, 0xd0fc, 0x0040, + 0x149b, 0x007e, 0x1078, 0x1d82, 0x007f, 0x0040, 0x14a5, 0x2001, + 0x4007, 0x0078, 0x159f, 0x007e, 0x1078, 0x1d72, 0x007f, 0x0040, + 0x14a5, 0x2001, 0x4007, 0x0078, 0x159f, 0x7910, 0xd0fc, 0x00c0, + 0x14af, 0x2061, 0x4a40, 0xc19c, 0xc7fc, 0x0078, 0x14b3, 0x2061, + 0x4a80, 0xc19d, 0xc7fd, 0x6064, 0xa005, 0x00c0, 0x14f7, 0x7912, + 0x6083, 0x0000, 0x7828, 0xc0fc, 0xa086, 0x0018, 0x00c0, 0x14c4, + 0x0c7e, 0x1078, 0x1b13, 0x0c7f, 0x782b, 0x0000, 0x607c, 0xa065, + 0x0040, 0x14dd, 0x0c7e, 0x609c, 0x1078, 0x1e5d, 0x0c7f, 0x609f, + 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, 0x6087, 0x0103, 0x1078, + 0x1d92, 0x00c0, 0x14f1, 0x1078, 0x1de4, 0x7810, 0xd09c, 0x00c0, + 0x14e5, 0x2061, 0x4a40, 0x0078, 0x14e9, 0x2061, 0x4a80, 0xc09c, + 0x7812, 0x607f, 0x0000, 0x60d4, 0xd0dc, 0x0040, 0x14f5, 0xc0dc, + 0x60d6, 0x2001, 0x4005, 0x0078, 0x159f, 0x0078, 0x159d, 0x007c, + 0x7810, 0xd0f4, 0x0040, 0x1500, 0x2001, 0x4007, 0x0078, 0x159f, + 0xa006, 0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, 0xa08a, + 0x0040, 0x00c8, 0x150d, 0x0079, 0x1514, 0x2100, 0xa08a, 0x0040, + 0x00c8, 0x15ab, 0x0079, 0x1554, 0x159d, 0x15f3, 0x15bc, 0x162b, + 0x1663, 0x1663, 0x15b3, 0x1c57, 0x166e, 0x15ab, 0x15c0, 0x15c2, + 0x15c4, 0x15c6, 0x1c5c, 0x15ab, 0x167c, 0x16d4, 0x1b35, 0x1c51, + 0x15c8, 0x19a7, 0x19e9, 0x1a1f, 0x1a6b, 0x1962, 0x196f, 0x1983, + 0x1996, 0x17a4, 0x1cdc, 0x1706, 0x1713, 0x171f, 0x172b, 0x1741, + 0x174d, 0x1750, 0x175c, 0x1768, 0x1770, 0x178c, 0x1798, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x17b1, 0x17c3, 0x17df, 0x1815, 0x183d, + 0x184d, 0x1850, 0x1881, 0x18b2, 0x18c4, 0x1931, 0x1941, 0x1d32, + 0x15ab, 0x15ab, 0x15ab, 0x1951, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x1c81, 0x1c87, 0x15ab, 0x15ab, 0x15ab, 0x1c8b, 0x1cd8, + 0x15ab, 0x15ab, 0x1ce8, 0x1cf7, 0x15ed, 0x165d, 0x1676, 0x16ce, + 0x1b2f, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x1d39, 0x1c73, 0x1c7d, + 0x15ab, 0x15ab, 0x1d02, 0x1d1b, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x15ab, + 0x15ab, 0x15ab, 0x15ab, 0x15ab, 0x72ca, 0x71c6, 0x2001, 0x4006, + 0x0078, 0x159f, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, + 0x0068, 0x15a0, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, + 0x2091, 0x4080, 0x007c, 0x70c3, 0x4001, 0x0078, 0x15a0, 0x70c3, + 0x4006, 0x0078, 0x15a0, 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, + 0x0005, 0x53a3, 0x0078, 0x159d, 0x70c4, 0x70c3, 0x0004, 0x007a, + 0x0078, 0x159d, 0x0078, 0x159d, 0x0078, 0x159d, 0x0078, 0x159d, + 0x2091, 0x8000, 0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, + 0x70cf, 0x2020, 0x70d3, 0x0008, 0x2001, 0x0009, 0x70d6, 0x2079, + 0x0000, 0x781b, 0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, + 0x041a, 0x2051, 0x0445, 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, + 0x5000, 0x2091, 0x4080, 0x0078, 0x0418, 0x75d8, 0x74dc, 0x75da, + 0x74de, 0x0078, 0x15f6, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, + 0x73cc, 0x70c4, 0x20a0, 0x2099, 0x0030, 0x7003, 0x0001, 0x7007, + 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, + 0x0040, 0x159d, 0xa182, 0x0040, 0x00c8, 0x1610, 0x2120, 0xa006, + 0x2008, 0x8403, 0x7012, 0x7007, 0x0004, 0x7007, 0x0001, 0x7008, + 0xd0fc, 0x0040, 0x1617, 0x7007, 0x0002, 0xa084, 0x01e0, 0x0040, + 0x1625, 0x70c3, 0x4002, 0x0078, 0x15a0, 0x24a8, 0x53a5, 0x0078, + 0x1607, 0x0078, 0x159d, 0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, + 0x73cc, 0x70c4, 0x2098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x7007, + 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040, 0x7007, + 0x0006, 0x81ff, 0x0040, 0x159d, 0xa182, 0x0040, 0x00c8, 0x164a, + 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007, + 0x0001, 0x7008, 0xd0fc, 0x0040, 0x1651, 0xa084, 0x01e0, 0x0040, + 0x163f, 0x70c3, 0x4002, 0x0078, 0x15a0, 0x75d8, 0x74dc, 0x75da, + 0x74de, 0x0078, 0x162e, 0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, + 0x00c0, 0x166b, 0x200a, 0x72ca, 0x0078, 0x159c, 0x70c7, 0x0008, + 0x70cb, 0x0009, 0x70cf, 0x0000, 0x0078, 0x159d, 0x75d8, 0x76dc, + 0x75da, 0x76de, 0x0078, 0x167f, 0x2029, 0x0000, 0x2530, 0x70c4, + 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, + 0x0040, 0x16c9, 0x8001, 0x7872, 0xa084, 0xfc00, 0x0040, 0x1697, + 0x78ac, 0xc085, 0x78ae, 0x2001, 0x4005, 0x0078, 0x159f, 0x7b7e, + 0x7a7a, 0x7e86, 0x7d82, 0x7c76, 0xa48c, 0xff00, 0x0040, 0x16af, + 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, 0x810f, 0xa118, 0xa291, + 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x0078, 0x16b9, 0x8407, + 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, + 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605, 0x0040, 0x16c3, + 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, 0x78ae, 0x0078, + 0x16cc, 0x78ac, 0xc085, 0x78ae, 0x0078, 0x159d, 0x75d8, 0x76dc, + 0x75da, 0x76de, 0x0078, 0x16d7, 0x2029, 0x0000, 0x2530, 0x70c4, + 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, + 0x0040, 0x1701, 0x8001, 0x7892, 0xa084, 0xfc00, 0x0040, 0x16ef, + 0x78ac, 0xc0c5, 0x78ae, 0x2001, 0x4005, 0x0078, 0x159f, 0x7a9a, + 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0040, 0x16fa, 0x7a10, + 0xc2c5, 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0078, + 0x1704, 0x78ac, 0xc0c5, 0x78ae, 0x0078, 0x159d, 0x2009, 0x0000, + 0x786c, 0xa065, 0x0040, 0x1710, 0x8108, 0x6000, 0x0078, 0x1709, + 0x7ac4, 0x0078, 0x159b, 0x2009, 0x4a48, 0x210c, 0x7810, 0xd0ec, + 0x00c0, 0x159c, 0x2011, 0x4a88, 0x2214, 0x0078, 0x159b, 0x2009, + 0x4a49, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2011, 0x4a89, + 0x2214, 0x0078, 0x159b, 0x2061, 0x4a40, 0x6128, 0x622c, 0x8214, + 0x8214, 0x8214, 0x7810, 0xd0ec, 0x00c0, 0x173f, 0x2061, 0x4a80, + 0x6328, 0x73da, 0x632c, 0x831c, 0x831c, 0x831c, 0x73de, 0x0078, + 0x159b, 0x2009, 0x4a4c, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, + 0x2011, 0x4a8c, 0x2214, 0x0078, 0x159b, 0x7918, 0x0078, 0x159c, + 0x2009, 0x4a4d, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2011, + 0x4a8d, 0x2214, 0x0078, 0x159b, 0x2009, 0x4a4e, 0x210c, 0x7810, + 0xd0ec, 0x00c0, 0x159c, 0x2011, 0x4a8e, 0x2214, 0x0078, 0x159b, + 0x7920, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x7a24, 0x0078, 0x159b, + 0x71c4, 0xd1fc, 0x00c0, 0x1778, 0x2011, 0x4ec0, 0x0078, 0x177a, + 0x2011, 0x4f40, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xa268, 0x6a00, 0x6804, 0xd09c, 0x0040, 0x1789, 0x6b08, 0x0078, + 0x178a, 0x6b0c, 0x0078, 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, + 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x159a, + 0x2061, 0x4a40, 0x6118, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2061, + 0x4a80, 0x6218, 0x0078, 0x159b, 0x77c4, 0x1078, 0x1e02, 0x2091, + 0x8000, 0x6908, 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0078, + 0x159a, 0x71c4, 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x00c8, + 0x1595, 0x1078, 0x2729, 0xa384, 0x4000, 0x0040, 0x17c1, 0xa295, + 0x0020, 0x0078, 0x159a, 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, + 0x00c8, 0x1595, 0xd1bc, 0x00c0, 0x17d2, 0x2011, 0x4a48, 0x2204, + 0x0078, 0x17d6, 0x2011, 0x4a88, 0x2204, 0xc0bd, 0x007e, 0x2100, + 0xc0bc, 0x2012, 0x1078, 0x2686, 0x017f, 0x0078, 0x159c, 0x71c4, + 0x2021, 0x4a49, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0078, 0x17ee, + 0x71c8, 0x2021, 0x4a89, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x180d, + 0x20a9, 0x0008, 0x2204, 0xa106, 0x0040, 0x17fd, 0x8210, 0x00f0, + 0x17f2, 0x71c4, 0x72c8, 0x0078, 0x1594, 0xa292, 0x180d, 0x027e, + 0x2122, 0x017f, 0x1078, 0x26a7, 0x7810, 0xd0ec, 0x00c0, 0x180b, + 0xd3fc, 0x0040, 0x17e8, 0x0078, 0x159d, 0x03e8, 0x00fa, 0x01f4, + 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061, 0x4a40, 0x6128, + 0x622c, 0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, + 0x8003, 0x8003, 0x602e, 0x7810, 0xd0ec, 0x00c0, 0x183b, 0x027e, + 0x017e, 0x2061, 0x4a80, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, + 0x70d8, 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, + 0x72de, 0x017f, 0x027f, 0x0078, 0x159b, 0x2061, 0x4a40, 0x6130, + 0x70c4, 0x6032, 0x7810, 0xd0ec, 0x00c0, 0x159c, 0x2061, 0x4a80, + 0x6230, 0x70c8, 0x6032, 0x0078, 0x159b, 0x7918, 0x0078, 0x159c, + 0x71c4, 0xa184, 0xffcf, 0x0040, 0x185c, 0x7810, 0xd0ec, 0x00c0, + 0x1595, 0x72c8, 0x0078, 0x1594, 0x2011, 0x4a4d, 0x2204, 0x2112, + 0x007e, 0x2019, 0x0000, 0x1078, 0x270e, 0x7810, 0xd0ec, 0x0040, + 0x186c, 0x017f, 0x0078, 0x159c, 0x71c8, 0xa184, 0xffcf, 0x0040, + 0x1875, 0x2110, 0x71c4, 0x0078, 0x1594, 0x2011, 0x4a8d, 0x2204, + 0x2112, 0x007e, 0xc3fd, 0x1078, 0x270e, 0x027f, 0x017f, 0x0078, + 0x159b, 0x71c4, 0xa182, 0x0010, 0x0048, 0x188d, 0x7810, 0xd0ec, + 0x00c0, 0x1595, 0x72c8, 0x0078, 0x1594, 0x2011, 0x4a4e, 0x2204, + 0x007e, 0x2112, 0x2019, 0x0000, 0x1078, 0x26ec, 0x7810, 0xd0ec, + 0x0040, 0x189d, 0x017f, 0x0078, 0x159c, 0x71c8, 0xa182, 0x0010, + 0x0048, 0x18a6, 0x2110, 0x71c4, 0x0078, 0x1594, 0x2011, 0x4a8e, + 0x2204, 0x007e, 0x2112, 0xc3fd, 0x1078, 0x26ec, 0x027f, 0x017f, + 0x0078, 0x159b, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x1594, + 0xa284, 0xfffd, 0x00c0, 0x1594, 0x2100, 0x7920, 0x7822, 0x2200, + 0x7a24, 0x7826, 0x0078, 0x159b, 0x71c4, 0xd1fc, 0x00c0, 0x18cc, + 0x2011, 0x4ec0, 0x0078, 0x18ce, 0x2011, 0x4f40, 0x8107, 0xa084, + 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x2019, 0x0000, 0x72c8, + 0xa284, 0x0080, 0x0040, 0x18e2, 0x6c14, 0x84ff, 0x00c0, 0x18e2, + 0x6817, 0x0040, 0xa284, 0x0040, 0x0040, 0x18ec, 0x6c10, 0x84ff, + 0x00c0, 0x18ec, 0x6813, 0x0001, 0x6800, 0x007e, 0xa226, 0x0040, + 0x1909, 0x6a02, 0xd4ec, 0x0040, 0x18f6, 0xc3a5, 0xd4e4, 0x0040, + 0x18fa, 0xc39d, 0xd4f4, 0x0040, 0x1909, 0x810f, 0xd2f4, 0x0040, + 0x1905, 0x1078, 0x276b, 0x0078, 0x1909, 0x1078, 0x2749, 0x0078, + 0x1909, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1929, 0xa2a4, 0x00ff, + 0x7814, 0xd0e4, 0x00c0, 0x191c, 0xa482, 0x0028, 0x0048, 0x1926, + 0x0040, 0x1926, 0x0078, 0x1920, 0xa482, 0x0043, 0x0048, 0x1926, + 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x1596, 0x6a0a, 0xa39d, + 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, 0x0078, + 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a14, 0x6b1c, + 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, + 0x159a, 0x70c4, 0x2061, 0x4a40, 0x6118, 0x601a, 0x7810, 0xd0ec, + 0x00c0, 0x159c, 0x70c8, 0x2061, 0x4a80, 0x6218, 0x601a, 0x0078, + 0x159b, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x1595, + 0x1078, 0x278d, 0xa384, 0x4000, 0x0040, 0x1960, 0xa295, 0x0020, + 0x0078, 0x159a, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a08, + 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, + 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, + 0x6804, 0xa005, 0x0040, 0x197e, 0x1078, 0x25de, 0x2091, 0x8001, + 0x2708, 0x0078, 0x159b, 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, + 0x6a08, 0xc295, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1991, 0x1078, + 0x25de, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, 0x2041, + 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, + 0x1e1d, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078, 0x159b, 0x77c4, + 0x7814, 0xd0e4, 0x00c0, 0x19bb, 0xd7fc, 0x0040, 0x19b5, 0x1078, + 0x1d82, 0x0040, 0x19bb, 0x0078, 0x159f, 0x1078, 0x1d72, 0x0040, + 0x19bb, 0x0078, 0x159f, 0x73c8, 0x72cc, 0x77c6, 0x73ca, 0x72ce, + 0x1078, 0x1e9a, 0x00c0, 0x19e5, 0x6818, 0xa005, 0x0040, 0x19df, + 0x2708, 0x077e, 0x1078, 0x27bd, 0x077f, 0x00c0, 0x19df, 0x2001, + 0x0015, 0xd7fc, 0x00c0, 0x19d8, 0x2061, 0x4a40, 0x0078, 0x19db, + 0xc0fd, 0x2061, 0x4a80, 0x782a, 0x2091, 0x8001, 0x007c, 0x2091, + 0x8001, 0x2001, 0x4005, 0x0078, 0x159f, 0x2091, 0x8001, 0x0078, + 0x159d, 0x77c4, 0x7814, 0xd0e4, 0x00c0, 0x19fd, 0xd7fc, 0x0040, + 0x19f7, 0x1078, 0x1d82, 0x0040, 0x19fd, 0x0078, 0x159f, 0x1078, + 0x1d72, 0x0040, 0x19fd, 0x0078, 0x159f, 0x77c6, 0x2041, 0x0021, + 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078, 0x1e1d, + 0x2009, 0x0016, 0xd7fc, 0x00c0, 0x1a11, 0x2061, 0x4a40, 0x0078, + 0x1a14, 0x2061, 0x4a80, 0xc1fd, 0x6067, 0x0003, 0x6776, 0x6083, + 0x000f, 0x792a, 0x1078, 0x25de, 0x2091, 0x8001, 0x007c, 0x77c8, + 0x77ca, 0x77c4, 0x77c6, 0x7814, 0xd0e4, 0x00c0, 0x1a36, 0xd7fc, + 0x0040, 0x1a30, 0x1078, 0x1d82, 0x0040, 0x1a36, 0x0078, 0x159f, + 0x1078, 0x1d72, 0x0040, 0x1a36, 0x0078, 0x159f, 0xa7bc, 0xff00, + 0x2091, 0x8000, 0x2009, 0x0017, 0xd7fc, 0x00c0, 0x1a43, 0x2061, + 0x4a40, 0x0078, 0x1a46, 0x2061, 0x4a80, 0xc1fd, 0x6067, 0x0002, + 0x6776, 0x6083, 0x000f, 0x792a, 0x1078, 0x25de, 0x2091, 0x8001, + 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0010, 0x2091, 0x8000, + 0x70c8, 0xa005, 0x0040, 0x1a5f, 0x60d4, 0xc0fd, 0x60d6, 0x1078, + 0x1e1d, 0x70c8, 0x683e, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1a5f, + 0x2091, 0x8001, 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x1a7f, 0x72c8, + 0xd284, 0x0040, 0x1a79, 0x1078, 0x1d82, 0x0040, 0x1a7f, 0x0078, + 0x159f, 0x1078, 0x1d72, 0x0040, 0x1a7f, 0x0078, 0x159f, 0x72c8, + 0x72ca, 0x78ac, 0xa084, 0x0003, 0x00c0, 0x1aaa, 0x2039, 0x0000, + 0xd284, 0x0040, 0x1a8c, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, + 0x2051, 0x0008, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6808, 0xc0d4, + 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x1a92, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, + 0x00c0, 0x1a92, 0x2091, 0x8000, 0x72c8, 0xd284, 0x00c0, 0x1abc, + 0x7810, 0xd0ec, 0x0040, 0x1ab8, 0x2069, 0x0100, 0x0078, 0x1abe, + 0x2069, 0x0200, 0x0078, 0x1abe, 0x2069, 0x0100, 0x6830, 0xd0b4, + 0x0040, 0x1ada, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, + 0x0040, 0x1acc, 0x00f0, 0x1ac6, 0x684b, 0x0009, 0x20a9, 0x0014, + 0x6848, 0xd084, 0x0040, 0x1ad6, 0x00f0, 0x1ad0, 0x20a9, 0x00fa, + 0x00f0, 0x1ad8, 0x2079, 0x4a00, 0x2009, 0x0018, 0x72c8, 0xd284, + 0x00c0, 0x1ae6, 0x2061, 0x4a40, 0x0078, 0x1ae9, 0x2061, 0x4a80, + 0xc1fd, 0x792a, 0x6067, 0x0001, 0x6083, 0x000f, 0x60a7, 0x0000, + 0x60a8, 0x60b2, 0x60b6, 0x60d4, 0xd0b4, 0x0040, 0x1b03, 0xc0b4, + 0x60d6, 0x0c7e, 0x60b8, 0xa065, 0x6008, 0xc0d4, 0x600a, 0x6018, + 0x8001, 0x601a, 0x0c7f, 0x60d4, 0xa084, 0x77ff, 0x60d6, 0x78ac, + 0xc08d, 0x78ae, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0047, + 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x1b1a, 0x2069, 0x4a40, + 0x0078, 0x1b1c, 0x2069, 0x4a80, 0x78ac, 0xc08c, 0x78ae, 0xd084, + 0x00c0, 0x1b26, 0x0d7e, 0x1078, 0x1efa, 0x0d7f, 0x71c4, 0x71c6, + 0x6916, 0x81ff, 0x00c0, 0x1b2e, 0x68a7, 0x0001, 0x007c, 0x75d8, + 0x74dc, 0x75da, 0x74de, 0x0078, 0x1b38, 0x2029, 0x0000, 0x2520, + 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4a00, + 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x1078, 0x1ddb, 0x0040, 0x1c3b, + 0x20a9, 0x0005, 0x20a1, 0x4a14, 0x2091, 0x8000, 0x41a1, 0x2091, + 0x8001, 0x2009, 0x0040, 0x1078, 0x1fcf, 0x0040, 0x1b5b, 0x1078, + 0x1de4, 0x0078, 0x1c3b, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, + 0x00c0, 0x1b66, 0x007e, 0x1078, 0x234b, 0x007f, 0xa084, 0xff00, + 0x8007, 0x8009, 0x0040, 0x1bda, 0x0c7e, 0x2c68, 0x1078, 0x1ddb, + 0x0040, 0x1bac, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x1b6d, 0x609f, + 0x0000, 0x0c7f, 0x0c7e, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, + 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, + 0x7cda, 0x7bd6, 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1bd9, + 0x2009, 0x0040, 0x1078, 0x1fcf, 0x00c0, 0x1bc3, 0x6004, 0xa084, + 0x00ff, 0xa086, 0x0002, 0x00c0, 0x1bac, 0x6004, 0xa084, 0x00ff, + 0xa086, 0x000a, 0x00c0, 0x1ba8, 0x017e, 0x1078, 0x2347, 0x017f, + 0x2d00, 0x6002, 0x0078, 0x1b7b, 0x0c7f, 0x0c7e, 0x609c, 0x1078, + 0x1e5d, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, + 0x6008, 0xc0cd, 0x600a, 0x6004, 0x6086, 0x1078, 0x1d92, 0x1078, + 0x1de4, 0x0078, 0x1c3b, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e5d, + 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c3f, 0x2009, 0x0018, 0x6087, + 0x0103, 0x601b, 0x0003, 0x1078, 0x1d92, 0x1078, 0x1de4, 0x0078, + 0x1c3b, 0x0c7f, 0x7814, 0xd0e4, 0x00c0, 0x1bff, 0x6114, 0xd1fc, + 0x0040, 0x1be8, 0x1078, 0x1d82, 0x0040, 0x1bff, 0x0078, 0x1bec, + 0x1078, 0x1d72, 0x0040, 0x1bff, 0x2029, 0x0000, 0x2520, 0x2009, + 0x0018, 0x73c8, 0x72cc, 0x6087, 0x0103, 0x601b, 0x0021, 0x1078, + 0x1d92, 0x1078, 0x1de4, 0x2001, 0x4007, 0x0078, 0x159f, 0x74c4, + 0x73c8, 0x72cc, 0x6014, 0x2091, 0x8000, 0x0e7e, 0x2009, 0x0012, + 0xd0fc, 0x00c0, 0x1c0f, 0x2071, 0x4a40, 0x0078, 0x1c12, 0x2071, + 0x4a80, 0xc1fd, 0x792a, 0x7067, 0x0005, 0x71d4, 0xa18c, 0xf77f, + 0x71d6, 0x736a, 0x726e, 0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, + 0x707e, 0xa02e, 0x2530, 0x611c, 0xa184, 0x0060, 0x0040, 0x1c2a, + 0x1078, 0x43c1, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, + 0x0000, 0x60b3, 0x0000, 0x6714, 0x6023, 0x0000, 0x1078, 0x25de, + 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x15a0, 0x20a9, + 0x0005, 0x2099, 0x4a14, 0x2091, 0x8000, 0x530a, 0x2091, 0x8001, + 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, + 0x007c, 0x71c4, 0x70c7, 0x0000, 0x791e, 0x0078, 0x159d, 0x71c4, + 0x71c6, 0x2168, 0x0078, 0x1c5e, 0x2069, 0x1000, 0x690c, 0xa016, + 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1c60, 0xa285, 0x0000, + 0x00c0, 0x1c6e, 0x70c3, 0x4000, 0x0078, 0x1c70, 0x70c3, 0x4003, + 0x70ca, 0x0078, 0x15a0, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, + 0x00c8, 0x1595, 0x7966, 0x0078, 0x159d, 0x7964, 0x71c6, 0x0078, + 0x159d, 0x7900, 0x71c6, 0x71c4, 0x7902, 0x0078, 0x159d, 0x7900, + 0x71c6, 0x0078, 0x159d, 0x70c4, 0xd08c, 0x0040, 0x1c94, 0x7a10, + 0xd2ec, 0x00c0, 0x1c94, 0xc08c, 0x2011, 0x0000, 0xa08c, 0x000d, + 0x0040, 0x1ca8, 0x810c, 0x0048, 0x1ca4, 0x8210, 0x810c, 0x810c, + 0x0048, 0x1ca4, 0x8210, 0x810c, 0x81ff, 0x00c0, 0x1596, 0x8210, + 0x7a0e, 0xd28c, 0x0040, 0x1cd4, 0x7910, 0xc1cd, 0x7912, 0x2009, + 0x0021, 0x2019, 0x0003, 0xd284, 0x0040, 0x1cce, 0x8108, 0x2019, + 0x0041, 0x2011, 0x924e, 0x2312, 0x2019, 0x0042, 0x8210, 0x2312, + 0x2019, 0x0043, 0x8210, 0x2312, 0x2019, 0x0046, 0x8210, 0x2312, + 0x2019, 0x0047, 0x8210, 0x2312, 0x2019, 0x0006, 0x2011, 0x9253, + 0x2112, 0x2011, 0x9273, 0x2312, 0x7904, 0x7806, 0x0078, 0x159c, + 0x7804, 0x70c6, 0x0078, 0x159d, 0x2091, 0x8000, 0x2019, 0x0000, + 0x2011, 0x0000, 0x2009, 0x0000, 0x2091, 0x8001, 0x0078, 0x159a, + 0x77c4, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6830, 0xa084, 0xff00, + 0x8007, 0x2010, 0x2091, 0x8001, 0x2708, 0x0078, 0x159b, 0x77c4, + 0x1078, 0x1e02, 0x2091, 0x8000, 0x6a34, 0x2091, 0x8001, 0x2708, + 0x0078, 0x159b, 0x77c4, 0x077e, 0xa7bc, 0xff00, 0x20a9, 0x0008, + 0x72c8, 0x8217, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6c30, 0x6a32, + 0x2091, 0x8001, 0x8738, 0x00f0, 0x1d0a, 0x077f, 0x2708, 0x8427, + 0x2410, 0x0078, 0x159b, 0x77c4, 0x077e, 0xa7bc, 0xff00, 0x20a9, + 0x0008, 0x72c8, 0x1078, 0x1e02, 0x2091, 0x8000, 0x6c34, 0x6a36, + 0x2091, 0x8001, 0x8738, 0x00f0, 0x1d22, 0x077f, 0x2708, 0x2410, + 0x0078, 0x159b, 0x2011, 0x4a3c, 0x220c, 0x70c4, 0x2012, 0x0078, + 0x159c, 0x71c4, 0xd1fc, 0x00c0, 0x1d41, 0x2011, 0x4ec0, 0x0078, + 0x1d43, 0x2011, 0x4f40, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, + 0x8003, 0xa268, 0x6a14, 0xd2b4, 0x0040, 0x1d52, 0x2011, 0x0001, + 0x0078, 0x1d54, 0x2011, 0x0000, 0x6b0c, 0x0078, 0x159a, 0x017e, + 0x7814, 0xd0f4, 0x0040, 0x1d64, 0x2001, 0x4007, 0x70db, 0x0000, + 0xa18d, 0x0001, 0x0078, 0x1d70, 0xd0fc, 0x0040, 0x1d6f, 0x2001, + 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078, 0x1d70, 0xa006, + 0x017f, 0x007c, 0x017e, 0x7814, 0xd0f4, 0x0040, 0x1d7f, 0x2001, + 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0078, 0x1d80, 0xa006, + 0x017f, 0x007c, 0x017e, 0x7814, 0xd0fc, 0x0040, 0x1d8f, 0x2001, + 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078, 0x1d90, 0xa006, + 0x017f, 0x007c, 0x7112, 0x721a, 0x731e, 0x7810, 0xd0c4, 0x0040, + 0x1d9b, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108, 0x810c, 0x81a9, + 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084, 0x20a2, 0x53a6, + 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0040, 0x1db8, 0x810f, + 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, 0x1dbb, + 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211, + 0x7d10, 0xd5c4, 0x0040, 0x1dc8, 0x7b84, 0xa319, 0x7c80, 0xa421, + 0x7008, 0xd0fc, 0x0040, 0x1dc8, 0x7003, 0x0001, 0x7007, 0x0006, + 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0040, 0x1dd8, 0x7322, 0x7426, + 0xa084, 0x01e0, 0x007c, 0x7848, 0xa065, 0x0040, 0x1de3, 0x2c04, + 0x784a, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x4a00, 0x7848, + 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1def, 0x1078, 0x28ec, 0x784a, + 0x0f7f, 0x007c, 0x2011, 0x9400, 0x7a4a, 0x7bc4, 0x8319, 0x0040, + 0x1dff, 0xa280, 0x0032, 0x2012, 0x2010, 0x0078, 0x1df6, 0x2013, + 0x0000, 0x007c, 0x017e, 0x027e, 0xd7fc, 0x00c0, 0x1e0b, 0x2011, + 0x4fc0, 0x0078, 0x1e0d, 0x2011, 0x6fc0, 0xa784, 0x0f00, 0x800b, + 0xa784, 0x001f, 0x0040, 0x1e18, 0x8003, 0x8003, 0x8003, 0x8003, + 0xa105, 0xa268, 0x027f, 0x017f, 0x007c, 0x1078, 0x1e02, 0x2900, + 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef, 0xa80d, 0x690a, + 0xd7fc, 0x00c0, 0x1e2f, 0x2009, 0x4a53, 0x0078, 0x1e31, 0x2009, + 0x4a93, 0x210c, 0x6804, 0xa005, 0x0040, 0x1e41, 0xa116, 0x00c0, + 0x1e41, 0x2060, 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, + 0x1e44, 0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1e59, + 0x6000, 0x6806, 0x1078, 0x1e6f, 0x1078, 0x201b, 0x6810, 0x7908, + 0x8109, 0x790a, 0x8001, 0x6812, 0x00c0, 0x1e44, 0x7910, 0xc1a5, + 0x7912, 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040, 0x1e6e, + 0x2008, 0x609c, 0xa005, 0x0040, 0x1e6b, 0x2062, 0x609f, 0x0000, + 0xa065, 0x0078, 0x1e61, 0x7848, 0x794a, 0x2062, 0x007c, 0x6007, + 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, 0xac80, 0x0005, 0x20a0, + 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022, 0x007c, + 0x0e7e, 0xd7fc, 0x00c0, 0x1e8a, 0x2071, 0x4a40, 0x2031, 0x4ac0, + 0x0078, 0x1e8e, 0x2071, 0x4a80, 0x2031, 0x4cc0, 0x7050, 0xa08c, + 0x0200, 0x00c0, 0x1e98, 0xa608, 0x2d0a, 0x8000, 0x7052, 0xa006, + 0x0e7f, 0x007c, 0x0f7e, 0xd7fc, 0x00c0, 0x1ea2, 0x2079, 0x4a40, + 0x0078, 0x1ea4, 0x2079, 0x4a80, 0x1078, 0x1e02, 0x2091, 0x8000, + 0x6804, 0x780a, 0xa065, 0x0040, 0x1ef8, 0x0078, 0x1eb6, 0x2c00, + 0x780a, 0x2060, 0x6000, 0xa065, 0x0040, 0x1ef8, 0x6010, 0xa306, + 0x00c0, 0x1eaf, 0x600c, 0xa206, 0x00c0, 0x1eaf, 0x2c28, 0x784c, + 0xac06, 0x00c0, 0x1ec5, 0x0078, 0x1ef5, 0x6804, 0xac06, 0x00c0, + 0x1ed3, 0x6000, 0x2060, 0x6806, 0xa005, 0x00c0, 0x1ed3, 0x6803, + 0x0000, 0x0078, 0x1edd, 0x6400, 0x7808, 0x2060, 0x6402, 0xa486, + 0x0000, 0x00c0, 0x1edd, 0x2c00, 0x6802, 0x2560, 0x0f7f, 0x1078, + 0x1e6f, 0x0f7e, 0x601b, 0x0005, 0x6023, 0x0020, 0x0f7f, 0x1078, + 0x201b, 0x0f7e, 0x7908, 0x8109, 0x790a, 0x6810, 0x8001, 0x6812, + 0x00c0, 0x1ef5, 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff, 0xa005, + 0x0f7f, 0x007c, 0x077e, 0x2700, 0x2039, 0x0000, 0xd0fc, 0x0040, + 0x1f02, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, + 0x2091, 0x8000, 0x1078, 0x1e1d, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x1f0a, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, + 0x00c0, 0x1f0a, 0x2091, 0x8001, 0x077f, 0x007c, 0x2061, 0x0000, + 0x6018, 0xd084, 0x00c0, 0x1f3e, 0x7810, 0xd08c, 0x0040, 0x1f2f, + 0xc08c, 0x7812, 0xc7fc, 0x2069, 0x4a40, 0x0078, 0x1f34, 0xc08d, + 0x7812, 0x2069, 0x4a80, 0xc7fd, 0x2091, 0x8000, 0x681c, 0x681f, + 0x0000, 0x2091, 0x8001, 0xa005, 0x00c0, 0x1f3f, 0x007c, 0xa08c, + 0xfff0, 0x0040, 0x1f45, 0x1078, 0x28ec, 0x0079, 0x1f47, 0x1f57, + 0x1f5a, 0x1f60, 0x1f64, 0x1f58, 0x1f68, 0x1f58, 0x1f58, 0x1f58, + 0x1f6e, 0x1f9f, 0x1fa3, 0x1fa9, 0x1f58, 0x1f58, 0x1f58, 0x007c, + 0x1078, 0x28ec, 0x1078, 0x1efa, 0x2001, 0x8001, 0x0078, 0x1fbe, + 0x2001, 0x8003, 0x0078, 0x1fbe, 0x2001, 0x8004, 0x0078, 0x1fbe, + 0x1078, 0x1efa, 0x2001, 0x8006, 0x0078, 0x1fbe, 0x2091, 0x8000, + 0x077e, 0xd7fc, 0x00c0, 0x1f7a, 0x2069, 0x4a40, 0x2039, 0x0009, + 0x0078, 0x1f7e, 0x2069, 0x4a80, 0x2039, 0x0009, 0x6800, 0xa086, + 0x0000, 0x0040, 0x1f88, 0x007f, 0x6f1e, 0x2091, 0x8001, 0x007c, + 0x6874, 0x077f, 0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, + 0x2051, 0x0010, 0x1078, 0x1e1d, 0x8738, 0xa784, 0x001f, 0x00c0, + 0x1f92, 0x2091, 0x8001, 0x2001, 0x800a, 0x0078, 0x1fbe, 0x2001, + 0x800c, 0x0078, 0x1fbe, 0x1078, 0x1efa, 0x2001, 0x800d, 0x0078, + 0x1fbe, 0x7814, 0xd0e4, 0x00c0, 0x1fbc, 0xd0ec, 0x0040, 0x1fb6, + 0xd7fc, 0x0040, 0x1fb6, 0x78ec, 0x0078, 0x1fb7, 0x78e4, 0x70c6, + 0x2001, 0x800e, 0x0078, 0x1fbe, 0x0078, 0x1f58, 0x70c2, 0xd7fc, + 0x00c0, 0x1fc6, 0x70db, 0x0000, 0x0078, 0x1fc8, 0x70db, 0x0001, + 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x007c, 0xac80, + 0x0001, 0x81ff, 0x0040, 0x1ffa, 0x2099, 0x0030, 0x20a0, 0x700c, + 0xa084, 0x03ff, 0x0040, 0x1fdc, 0x7018, 0x007e, 0x701c, 0x007e, + 0x7020, 0x007e, 0x7024, 0x007e, 0x7112, 0x81ac, 0x721a, 0x731e, + 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001, 0x7008, 0x800b, + 0x00c8, 0x1fee, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x1ffa, + 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, 0x007f, 0x7026, + 0x007f, 0x7022, 0x007f, 0x701e, 0x007f, 0x701a, 0x007c, 0x2011, + 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x6803, 0xfd00, 0x6807, + 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, + 0x00c0, 0x200b, 0x007c, 0x6004, 0x6086, 0x2c08, 0x2063, 0x0000, + 0x7868, 0xa005, 0x796a, 0x0040, 0x2028, 0x2c02, 0x0078, 0x2029, + 0x796e, 0x007c, 0x0c7e, 0x2061, 0x4a00, 0x6887, 0x0103, 0x2d08, + 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x203a, 0x2d02, + 0x0078, 0x203b, 0x616e, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x2c04, + 0x786e, 0xa005, 0x00c0, 0x2045, 0x786a, 0x2091, 0x8001, 0x609c, + 0xa005, 0x0040, 0x205e, 0x0c7e, 0x2060, 0x2008, 0x609c, 0xa005, + 0x0040, 0x205a, 0x2062, 0x609f, 0x0000, 0xa065, 0x609c, 0xa005, + 0x00c0, 0x2052, 0x7848, 0x794a, 0x2062, 0x0c7f, 0x7848, 0x2062, + 0x609f, 0x0000, 0xac85, 0x0000, 0x00c0, 0x2068, 0x1078, 0x28ec, + 0x784a, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, + 0x00c8, 0x2073, 0xa200, 0x00f0, 0x206e, 0x8086, 0x818e, 0x007c, + 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x2099, 0xa11a, 0x00c8, + 0x2099, 0x8213, 0x818d, 0x0048, 0x208c, 0xa11a, 0x00c8, 0x208d, + 0x00f0, 0x2081, 0x0078, 0x2091, 0xa11a, 0x2308, 0x8210, 0x00f0, + 0x2081, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, + 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x2095, 0x7d74, + 0x70d0, 0xa506, 0x0040, 0x2185, 0x7810, 0x2050, 0x7800, 0xd08c, + 0x0040, 0x20c1, 0xdaec, 0x0040, 0x20c1, 0x0e7e, 0x2091, 0x8000, + 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x20be, 0x7008, 0x0e7f, + 0xa086, 0x0008, 0x0040, 0x20c1, 0x0078, 0x2185, 0x0e7f, 0x0078, + 0x2185, 0x1078, 0x1ddb, 0x0040, 0x2185, 0xa046, 0x7970, 0x2500, + 0x8000, 0xa112, 0x2009, 0x0040, 0x00c8, 0x20d0, 0x0078, 0x20d7, + 0x72d0, 0xa206, 0x0040, 0x20d7, 0x8840, 0x2009, 0x0080, 0x0c7e, + 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9, 0x0020, 0xac80, + 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0040, 0x20e9, 0x1078, + 0x1ddb, 0x7008, 0xd0fc, 0x0040, 0x20e9, 0x7007, 0x0002, 0x2091, + 0x8001, 0xa08c, 0x01e0, 0x00c0, 0x2120, 0x53a5, 0x8cff, 0x00c0, + 0x20fe, 0x88ff, 0x0040, 0x216f, 0x0078, 0x2108, 0x2c00, 0x788e, + 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x53a5, 0x0078, 0x216f, + 0xa046, 0x7218, 0x731c, 0xdac4, 0x0040, 0x2110, 0x7420, 0x7524, + 0xa292, 0x0040, 0xa39b, 0x0000, 0xa4a3, 0x0000, 0xa5ab, 0x0000, + 0x721a, 0x731e, 0xdac4, 0x0040, 0x2120, 0x7422, 0x7526, 0xa006, + 0x7007, 0x0004, 0x0040, 0x216f, 0x8cff, 0x0040, 0x2129, 0x1078, + 0x1de4, 0x0c7f, 0x1078, 0x1de4, 0xa046, 0x7888, 0x8000, 0x788a, + 0xa086, 0x0002, 0x0040, 0x214f, 0x7a7c, 0x7b78, 0xdac4, 0x0040, + 0x213b, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004, 0x8004, 0xa210, + 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x721a, 0x731e, + 0xdac4, 0x0040, 0x2185, 0x7422, 0x7526, 0x0078, 0x2185, 0x6014, + 0xd0fc, 0x00c0, 0x2157, 0x2069, 0x4a40, 0x0078, 0x2159, 0x2069, + 0x4a80, 0x2091, 0x8000, 0x681f, 0x0002, 0x88ff, 0x0040, 0x2165, + 0xa046, 0x788c, 0x2060, 0x0078, 0x214f, 0x788b, 0x0000, 0x78ac, + 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0078, 0x2185, 0x0c7f, + 0x788b, 0x0000, 0x1078, 0x2319, 0x6004, 0xa084, 0x000f, 0x1078, + 0x2186, 0x88ff, 0x0040, 0x2183, 0x788c, 0x2060, 0x6004, 0xa084, + 0x000f, 0x1078, 0x2186, 0x0078, 0x209f, 0x007c, 0x0079, 0x2188, + 0x2198, 0x21b6, 0x21d4, 0x2198, 0x21e5, 0x21a9, 0x2198, 0x2198, + 0x2198, 0x21b4, 0x21d2, 0x2198, 0x2198, 0x2198, 0x2198, 0x2198, + 0x2039, 0x0400, 0x78bc, 0xa705, 0x78be, 0x6008, 0xa705, 0x600a, + 0x1078, 0x2228, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, 0x2303, + 0x007c, 0x78bc, 0xd0c4, 0x0040, 0x21af, 0x0078, 0x2198, 0x601c, + 0xc0bd, 0x601e, 0x0078, 0x21bc, 0x1078, 0x234b, 0x78bc, 0xd0c4, + 0x0040, 0x21bc, 0x0078, 0x2198, 0x78bf, 0x0000, 0x6004, 0x8007, + 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0040, 0x21cf, 0x1078, 0x2228, + 0x0040, 0x21cf, 0x78bc, 0xc0c5, 0x78be, 0x0078, 0x21d1, 0x0078, + 0x2247, 0x007c, 0x1078, 0x2347, 0x78bc, 0xa08c, 0x0e00, 0x00c0, + 0x21dc, 0xd0c4, 0x00c0, 0x21de, 0x0078, 0x2198, 0x1078, 0x2228, + 0x00c0, 0x21e4, 0x0078, 0x2247, 0x007c, 0x78bc, 0xd0c4, 0x0040, + 0x21eb, 0x0078, 0x2198, 0x78bf, 0x0000, 0x6714, 0x2011, 0x0001, + 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040, 0x220b, 0xa7bc, + 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040, 0x220b, 0xa7bc, + 0x8000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0040, + 0x220b, 0x0078, 0x2225, 0x1078, 0x1e02, 0x2d00, 0x2091, 0x8000, + 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde, 0x680a, + 0xade8, 0x0010, 0x2091, 0x8001, 0x00f0, 0x220e, 0x8211, 0x0040, + 0x2225, 0x20a9, 0x0100, 0x0078, 0x220e, 0x1078, 0x1de4, 0x007c, + 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6, 0x00c0, 0x2233, + 0x78ba, 0x0078, 0x223b, 0x689e, 0x2d00, 0x6002, 0x78b8, 0xad06, + 0x00c0, 0x223b, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x00c0, 0x2246, + 0x78bc, 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, 0x007c, 0x0e7e, + 0xa02e, 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2, + 0x2048, 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0040, 0x225a, + 0x1078, 0x43c1, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, + 0x4a80, 0xd7fc, 0x00c0, 0x2266, 0x2071, 0x4a40, 0xa784, 0x0f00, + 0x800b, 0xa784, 0x001f, 0x0040, 0x2271, 0x8003, 0x8003, 0x8003, + 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, 0x8007, 0xa084, 0x000f, + 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, 0x60c2, 0x2091, 0x8000, + 0x7810, 0xd0f4, 0x00c0, 0x228b, 0x6e08, 0xd684, 0x0040, 0x22a1, + 0xd9fc, 0x00c0, 0x22a1, 0x2091, 0x8001, 0x1078, 0x1e6f, 0x2091, + 0x8000, 0x1078, 0x201b, 0x2091, 0x8001, 0x7814, 0xd0e4, 0x00c0, + 0x2301, 0x7810, 0xd0f4, 0x0040, 0x2301, 0x601b, 0x0021, 0x0078, + 0x2301, 0x6024, 0xa096, 0x0001, 0x00c0, 0x22a8, 0x8000, 0x6026, + 0x6a10, 0x6814, 0xa202, 0x0048, 0x22bb, 0x0040, 0x22bb, 0x2091, + 0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078, + 0x2303, 0x0078, 0x2301, 0x2c08, 0xd9fc, 0x0040, 0x22de, 0x6800, + 0xa065, 0x0040, 0x22de, 0x6a04, 0x7000, 0xa084, 0x0002, 0x0040, + 0x22d9, 0x704c, 0xa206, 0x00c0, 0x22d9, 0x6b04, 0x2160, 0x2304, + 0x6002, 0xa005, 0x00c0, 0x22d5, 0x6902, 0x2260, 0x6102, 0x0078, + 0x22ea, 0x2160, 0x6202, 0x6906, 0x0078, 0x22ea, 0x6800, 0x6902, + 0xa065, 0x0040, 0x22e6, 0x6102, 0x0078, 0x22e7, 0x6906, 0x2160, + 0x6003, 0x0000, 0x2160, 0xd9fc, 0x0040, 0x22f1, 0xa6b4, 0xfffc, + 0x6e0a, 0x6810, 0x7d08, 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, + 0x8001, 0xd6b4, 0x0040, 0x2301, 0xa6b6, 0x0040, 0x6e0a, 0x1078, + 0x1e80, 0x0e7f, 0x007c, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, + 0x1078, 0x201b, 0x2091, 0x8001, 0x78b8, 0xa065, 0x0040, 0x2316, + 0x609c, 0x78ba, 0x609f, 0x0000, 0x0078, 0x2303, 0x78b6, 0x78ba, + 0x007c, 0x7970, 0x7874, 0x2818, 0xd384, 0x0040, 0x2323, 0x8000, + 0xa112, 0x0048, 0x2328, 0x8000, 0xa112, 0x00c8, 0x2338, 0xc384, + 0x7a7c, 0x721a, 0x7a78, 0x721e, 0xdac4, 0x0040, 0x2333, 0x7a84, + 0x7222, 0x7a80, 0x7226, 0xa006, 0xd384, 0x0040, 0x2338, 0x8000, + 0x7876, 0x70d2, 0x781c, 0xa005, 0x0040, 0x2346, 0x8001, 0x781e, + 0x00c0, 0x2346, 0x0068, 0x2346, 0x2091, 0x4080, 0x007c, 0x2039, + 0x235f, 0x0078, 0x234d, 0x2039, 0x2365, 0x2704, 0xa005, 0x0040, + 0x235e, 0xac00, 0x2068, 0x6908, 0x6810, 0x6912, 0x680a, 0x690c, + 0x6814, 0x6916, 0x680e, 0x8738, 0x0078, 0x234d, 0x007c, 0x0003, + 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015, 0x001b, 0x0000, + 0x2041, 0x0000, 0x780c, 0x0079, 0x236d, 0x2535, 0x2508, 0x2371, + 0x23e5, 0x2039, 0x9274, 0x2734, 0x7d10, 0x0078, 0x238c, 0x6084, + 0xa086, 0x0103, 0x00c0, 0x23ce, 0x6114, 0x6018, 0xa105, 0x00c0, + 0x23ce, 0x8603, 0xa080, 0x9255, 0x620c, 0x2202, 0x8000, 0x6210, + 0x2202, 0x1078, 0x203d, 0x8630, 0xa68e, 0x000f, 0x0040, 0x2454, + 0x786c, 0xa065, 0x00c0, 0x2377, 0x7808, 0xa602, 0x00c8, 0x239d, + 0xd5ac, 0x00c0, 0x239d, 0x263a, 0x007c, 0xa682, 0x0003, 0x00c8, + 0x2454, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, + 0x23c9, 0x2011, 0x9255, 0x2204, 0x70c6, 0x8210, 0x2204, 0x70ca, + 0xd684, 0x00c0, 0x23b9, 0x8210, 0x2204, 0x70da, 0x8210, 0x2204, + 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, + 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, 0x203b, 0x0000, + 0x007c, 0x7810, 0xc0ad, 0x7812, 0x0078, 0x2454, 0x263a, 0x1078, + 0x253f, 0x00c0, 0x254e, 0x786c, 0xa065, 0x00c0, 0x2377, 0x2091, + 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, 0x23e0, 0xc0ad, + 0x7812, 0x2091, 0x8001, 0x0078, 0x254e, 0x2039, 0x9274, 0x2734, + 0x7d10, 0x0078, 0x23fc, 0x6084, 0xa086, 0x0103, 0x00c0, 0x243d, + 0x6114, 0x6018, 0xa105, 0x00c0, 0x243d, 0xa680, 0x9255, 0x620c, + 0x2202, 0x1078, 0x203d, 0x8630, 0xa68e, 0x001e, 0x0040, 0x2454, + 0x786c, 0xa065, 0x00c0, 0x23eb, 0x7808, 0xa602, 0x00c8, 0x240d, + 0xd5ac, 0x00c0, 0x240d, 0x263a, 0x007c, 0xa682, 0x0006, 0x00c8, + 0x2454, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, + 0x2438, 0x2011, 0x9255, 0x2009, 0x924e, 0x26a8, 0x211c, 0x2204, + 0x201a, 0x8108, 0x8210, 0x00f0, 0x241e, 0xa685, 0x8030, 0x70c2, + 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, + 0x2091, 0x8001, 0xa006, 0x2009, 0x9275, 0x200a, 0x203a, 0x007c, + 0x7810, 0xc0ad, 0x7812, 0x0078, 0x2454, 0x263a, 0x1078, 0x253f, + 0x00c0, 0x254e, 0x786c, 0xa065, 0x00c0, 0x23eb, 0x2091, 0x8000, + 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040, 0x244f, 0xc0ad, 0x7812, + 0x2091, 0x8001, 0x0078, 0x254e, 0x2091, 0x8000, 0x7007, 0x0004, + 0x7994, 0x70d4, 0xa102, 0x0048, 0x2465, 0x0040, 0x246f, 0x7b90, + 0xa302, 0x00c0, 0x246f, 0x0078, 0x2468, 0x8002, 0x00c0, 0x246f, + 0x263a, 0x7810, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x007c, 0xa184, + 0xff00, 0x0040, 0x247c, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, + 0x8007, 0xa100, 0x0078, 0x247f, 0x8107, 0x8004, 0x8004, 0x7a9c, + 0xa210, 0x721a, 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, 0x0040, + 0x248f, 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, + 0x0030, 0x7003, 0x0000, 0x2009, 0x9254, 0x260a, 0x8109, 0x2198, + 0x2104, 0xd084, 0x0040, 0x249d, 0x8633, 0xa6b0, 0x0002, 0x26a8, + 0x53a6, 0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, + 0xa10a, 0x00c8, 0x24ac, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, + 0x0040, 0x24bb, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, + 0xa100, 0x0078, 0x24be, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, + 0x7a78, 0xa006, 0xa211, 0xd4c4, 0x0040, 0x24ca, 0x7b84, 0xa319, + 0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0040, 0x24ca, 0xa084, 0x01e0, + 0x0040, 0x24ef, 0x7d10, 0x2031, 0x9254, 0x2634, 0x78a8, 0x8000, + 0x78aa, 0xd08c, 0x00c0, 0x24e4, 0x7007, 0x0006, 0x7004, 0xd094, + 0x00c0, 0x24de, 0x0078, 0x2456, 0x2069, 0x4a47, 0x206b, 0x0003, + 0x78ac, 0xa085, 0x0300, 0x78ae, 0xa006, 0x0078, 0x24f8, 0x2030, + 0x75d6, 0x2091, 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, + 0x2091, 0x8001, 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, + 0x711a, 0x721e, 0xd5c4, 0x0040, 0x2507, 0x7322, 0x7426, 0x007c, + 0x6084, 0xa086, 0x0103, 0x00c0, 0x252b, 0x6114, 0x6018, 0xa105, + 0x00c0, 0x252b, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x252b, + 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, + 0x2091, 0x4080, 0x1078, 0x203d, 0x0068, 0x252a, 0x786c, 0xa065, + 0x00c0, 0x2508, 0x007c, 0x1078, 0x253f, 0x00c0, 0x254e, 0x786c, + 0xa065, 0x00c0, 0x2508, 0x0078, 0x254e, 0x1078, 0x253f, 0x00c0, + 0x254e, 0x786c, 0xa065, 0x00c0, 0x2535, 0x0078, 0x254e, 0x1078, + 0x2554, 0x00c0, 0x2546, 0xa085, 0x0001, 0x007c, 0x1078, 0x2563, + 0x00c0, 0x254c, 0x2041, 0x0001, 0x7d10, 0x007c, 0x88ff, 0x0040, + 0x2553, 0x2091, 0x4080, 0x007c, 0x7b90, 0x7994, 0x70d4, 0xa102, + 0x00c0, 0x255d, 0xa385, 0x0000, 0x007c, 0x0048, 0x2561, 0xa302, + 0x007c, 0x8002, 0x007c, 0x7810, 0xd0ec, 0x0040, 0x257b, 0x0e7e, + 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2578, + 0x7008, 0x0e7f, 0xa086, 0x0008, 0x0040, 0x257b, 0x0078, 0x25cc, + 0x0e7f, 0x0078, 0x25cc, 0xa184, 0xff00, 0x0040, 0x2588, 0x810f, + 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0078, 0x258b, + 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa210, + 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, 0x0018, 0x6028, 0xa005, + 0x0040, 0x259c, 0x2009, 0x0040, 0x1078, 0x1d92, 0x0040, 0x25be, + 0x78a8, 0x8000, 0x78aa, 0xd08c, 0x00c0, 0x25cc, 0x6014, 0xd0fc, + 0x00c0, 0x25ae, 0x2069, 0x4a40, 0x0078, 0x25b0, 0x2069, 0x4a80, + 0x2091, 0x8000, 0x681f, 0x0003, 0x78ab, 0x0000, 0x78ac, 0xa085, + 0x0300, 0x78ae, 0x2091, 0x8001, 0x0078, 0x25cc, 0x78ab, 0x0000, + 0x1078, 0x203d, 0x7990, 0x7894, 0x8000, 0xa10a, 0x00c8, 0x25c9, + 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071, 0x0010, 0x2091, 0x8001, + 0x007c, 0x2138, 0xd7fc, 0x00c0, 0x25d9, 0x2009, 0x4a59, 0x0078, + 0x25db, 0x2009, 0x4a99, 0x2091, 0x8000, 0x200a, 0x0f7e, 0xd7fc, + 0x00c0, 0x25f2, 0x2009, 0x4a40, 0x2001, 0x4a04, 0x2004, 0xd0ec, + 0x0040, 0x25ee, 0x2079, 0x0100, 0x0078, 0x25f6, 0x2079, 0x0200, + 0x0078, 0x25f6, 0x2009, 0x4a80, 0x2079, 0x0100, 0x2104, 0xa086, + 0x0000, 0x00c0, 0x260f, 0xd7fc, 0x00c0, 0x2602, 0x2009, 0x4a45, + 0x0078, 0x2604, 0x2009, 0x4a85, 0x2104, 0xa005, 0x00c0, 0x260f, + 0x7830, 0xa084, 0x00c0, 0x00c0, 0x260f, 0x781b, 0x0045, 0x0f7f, + 0x007c, 0x2009, 0x0002, 0x2069, 0x4a00, 0x6810, 0xd0ec, 0x00c0, + 0x2672, 0x2071, 0x4a80, 0x2079, 0x0100, 0x2021, 0x4cbf, 0x784b, + 0x000f, 0x2019, 0x4205, 0xd184, 0x0040, 0x2632, 0x6810, 0xd0ec, + 0x0040, 0x262e, 0x20a1, 0x012b, 0x0078, 0x2634, 0x20a1, 0x022b, + 0x0078, 0x2634, 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, 0x2641, + 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, 0x0078, + 0x2634, 0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, + 0x8020, 0x00f0, 0x2645, 0x7003, 0x0000, 0x017e, 0xd18c, 0x2009, + 0x0000, 0x0040, 0x2654, 0xc1bd, 0x1078, 0x283d, 0x017f, 0x7020, + 0xa084, 0x000f, 0x007e, 0x6814, 0xd0e4, 0x007f, 0x00c0, 0x2664, + 0xa085, 0x6340, 0x0078, 0x2666, 0xa085, 0x62c0, 0x7806, 0x780f, + 0x9200, 0x7843, 0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7456, + 0x7053, 0x0000, 0x8109, 0x0040, 0x2685, 0x2071, 0x4a40, 0x6810, + 0xd0ec, 0x0040, 0x267f, 0x2079, 0x0100, 0x0078, 0x2681, 0x2079, + 0x0200, 0x2021, 0x4abf, 0x0078, 0x261f, 0x007c, 0x017e, 0xd1bc, + 0x00c0, 0x269a, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, + 0x0040, 0x2696, 0x2011, 0x0101, 0x0078, 0x269c, 0x2011, 0x0201, + 0x0078, 0x269c, 0x2011, 0x0101, 0xa18c, 0x000f, 0x2204, 0xa084, + 0xfff0, 0xa105, 0x2012, 0x017f, 0x1078, 0x283d, 0x007c, 0xd3fc, + 0x00c0, 0x26ba, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, + 0x0040, 0x26b6, 0x2011, 0x0101, 0x0078, 0x26bc, 0x2011, 0x0201, + 0x0078, 0x26bc, 0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x00f0, + 0x26be, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, + 0x007c, 0x2019, 0x0002, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x0040, + 0x26d6, 0x8319, 0x2009, 0x0101, 0x0078, 0x26d8, 0x2009, 0x0101, + 0x20a9, 0x0005, 0x8213, 0x00f0, 0x26da, 0xa294, 0x00e0, 0x2104, + 0xa084, 0xff1f, 0xa205, 0x200a, 0x8319, 0x0040, 0x26eb, 0x2009, + 0x0201, 0x0078, 0x26d8, 0x007c, 0xd3fc, 0x00c0, 0x26ff, 0x007e, + 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x26fb, 0x2011, + 0x0101, 0x0078, 0x2701, 0x2011, 0x0201, 0x0078, 0x2701, 0x2011, + 0x0101, 0x20a9, 0x000c, 0x810b, 0x00f0, 0x2703, 0xa18c, 0xf000, + 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x007c, 0xd3fc, 0x00c0, + 0x2721, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x271d, 0x2011, 0x0102, 0x0078, 0x2723, 0x2011, 0x0202, 0x0078, + 0x2723, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, + 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x273d, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2739, 0x2061, 0x0100, 0x0078, + 0x273f, 0x2061, 0x0200, 0x0078, 0x273f, 0x2061, 0x0100, 0xc1bc, + 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x62ac, 0x63ac, 0x0c7f, + 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x275d, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2759, 0x2061, 0x0100, 0x0078, + 0x275f, 0x2061, 0x0200, 0x0078, 0x275f, 0x2061, 0x0100, 0xc1bc, + 0x8103, 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, + 0x60ae, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x277f, 0x007e, + 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x277b, 0x2061, + 0x0100, 0x0078, 0x2781, 0x2061, 0x0200, 0x0078, 0x2781, 0x2061, + 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, + 0xa085, 0x0020, 0x60ae, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, + 0x27a1, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, + 0x279d, 0x2061, 0x0100, 0x0078, 0x27a3, 0x2061, 0x0200, 0x0078, + 0x27a3, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, + 0x609a, 0x60a4, 0xa28c, 0x0020, 0x0040, 0x27b1, 0xc2ac, 0xa39d, + 0x4000, 0xc3fc, 0xd3b4, 0x00c0, 0x27b6, 0xc3fd, 0x62ae, 0x2010, + 0x60a4, 0x63ae, 0x2018, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, + 0x0e7e, 0x6818, 0xa005, 0x0040, 0x281b, 0xd1fc, 0x0040, 0x27cc, + 0x2061, 0x91d0, 0x0078, 0x27ce, 0x2061, 0x90c0, 0x1078, 0x2823, + 0x0040, 0x2801, 0x20a9, 0x0101, 0xd1fc, 0x0040, 0x27db, 0x2061, + 0x90d0, 0x0078, 0x27dd, 0x2061, 0x8fc0, 0x0c7e, 0x1078, 0x2823, + 0x0040, 0x27e8, 0x0c7f, 0x8c60, 0x00f0, 0x27dd, 0x0078, 0x281b, + 0x007f, 0xd1fc, 0x0040, 0x27f2, 0xa082, 0x90d0, 0x2071, 0x4a80, + 0x0078, 0x27f6, 0xa082, 0x8fc0, 0x2071, 0x4a40, 0x707a, 0x7176, + 0x2001, 0x0004, 0x7066, 0x7083, 0x000f, 0x1078, 0x25d1, 0x0078, + 0x2817, 0xd1fc, 0x00c0, 0x2808, 0x2071, 0x4a40, 0x0078, 0x280a, + 0x2071, 0x4a80, 0x6020, 0xc0dd, 0x6022, 0x7176, 0x2c00, 0x707e, + 0x2001, 0x0006, 0x7066, 0x7083, 0x000f, 0x1078, 0x25d1, 0x2001, + 0x0000, 0x0078, 0x281d, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, + 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040, 0x283a, 0x2060, + 0x6010, 0xa306, 0x00c0, 0x2837, 0x600c, 0xa206, 0x00c0, 0x2837, + 0x6014, 0xa106, 0x00c0, 0x2837, 0xa006, 0x0078, 0x283c, 0x6000, + 0x0078, 0x2824, 0xa085, 0x0001, 0x007c, 0x0f7e, 0x0e7e, 0x017e, + 0xd1bc, 0x00c0, 0x2855, 0x2079, 0x4a40, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2851, 0x2071, 0x0100, 0x0078, + 0x2859, 0x2071, 0x0200, 0x0078, 0x2859, 0x2079, 0x4a80, 0x2071, + 0x0100, 0x7920, 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x00c0, 0x2863, + 0x017f, 0x0078, 0x287e, 0x810b, 0x810b, 0x810b, 0x810b, 0x007f, + 0xd0bc, 0x00c0, 0x287b, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x2877, 0xa18d, 0x0f00, 0x0078, 0x287d, 0xa18d, + 0x0f00, 0x0078, 0x287d, 0xa18d, 0x0800, 0x2104, 0x0e7f, 0x0f7f, + 0x007c, 0x0e7e, 0x2001, 0x4a01, 0x2004, 0xd0ac, 0x00c0, 0x28ea, + 0x68e4, 0xd0ac, 0x0040, 0x28ea, 0xa084, 0x0006, 0x00c0, 0x28ea, + 0x6014, 0xd0fc, 0x00c0, 0x2898, 0x2071, 0x4ec0, 0x0078, 0x289a, + 0x2071, 0x4f40, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xae70, 0x7004, 0xa084, 0x000a, 0x00c0, 0x28ea, 0x7108, 0xa194, + 0xff00, 0x0040, 0x28ea, 0xa18c, 0x00ff, 0x2001, 0x000a, 0xa106, + 0x0040, 0x28cd, 0x2001, 0x000c, 0xa106, 0x0040, 0x28d1, 0x2001, + 0x0012, 0xa106, 0x0040, 0x28d5, 0x2001, 0x0014, 0xa106, 0x0040, + 0x28d9, 0x2001, 0x0019, 0xa106, 0x0040, 0x28dd, 0x2001, 0x0032, + 0xa106, 0x0040, 0x28e1, 0x0078, 0x28e5, 0x2009, 0x000c, 0x0078, + 0x28e7, 0x2009, 0x0012, 0x0078, 0x28e7, 0x2009, 0x0014, 0x0078, + 0x28e7, 0x2009, 0x0019, 0x0078, 0x28e7, 0x2009, 0x0020, 0x0078, + 0x28e7, 0x2009, 0x003f, 0x0078, 0x28e7, 0x2011, 0x0000, 0x2100, + 0xa205, 0x700a, 0x0e7f, 0x007c, 0x0068, 0x28ec, 0x2091, 0x8000, + 0x2071, 0x0000, 0x007e, 0x7018, 0xd084, 0x00c0, 0x28f3, 0x007f, + 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, + 0x0809, 0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, + 0x4080, 0x0078, 0x2909, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, + 0x708e, 0x7592, 0x7496, 0x769a, 0x779e, 0xa594, 0x003f, 0xd4f4, + 0x0040, 0x2920, 0xa784, 0x007d, 0x00c0, 0x417b, 0x1078, 0x28ec, + 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x292b, 0xa3a6, 0x0007, + 0x00c0, 0x28ec, 0x2418, 0x8507, 0xa084, 0x000f, 0x0079, 0x2930, + 0x2f45, 0x3035, 0x3060, 0x32c1, 0x363b, 0x36a1, 0x3741, 0x37bd, + 0x38a1, 0x398a, 0x2943, 0x2940, 0x2d2a, 0x2e43, 0x360e, 0x2940, + 0x1078, 0x28ec, 0x007c, 0xa006, 0x0078, 0x294d, 0x7808, 0xc08d, + 0x780a, 0xa006, 0x7002, 0x704e, 0x7046, 0x70d2, 0x7060, 0xa005, + 0x00c0, 0x2a64, 0x7064, 0xa084, 0x0007, 0x0079, 0x2957, 0x295f, + 0x29cf, 0x29d8, 0x29e3, 0x29ee, 0x2a4a, 0x29f9, 0x29cf, 0x7830, + 0xd0bc, 0x00c0, 0x2942, 0x71d4, 0xd1b4, 0x00c0, 0x29ac, 0x70a4, + 0xa086, 0x0001, 0x0040, 0x2942, 0x70b4, 0xa06d, 0x6800, 0xa065, + 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, + 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0040, 0x2982, 0x69bc, + 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0010, 0x0078, + 0x2bbd, 0x7060, 0xa005, 0x00c0, 0x2942, 0x0c7e, 0x0d7e, 0x70b4, + 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, + 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, + 0x0040, 0x29a5, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, + 0x2001, 0x0020, 0x0078, 0x2bbd, 0x1078, 0x411c, 0x00c0, 0x2942, + 0x781b, 0x005b, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x68bc, + 0x7042, 0xc1b4, 0x71d6, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x7003, + 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0x1078, + 0x411c, 0x00c0, 0x29d7, 0x781b, 0x0047, 0x7003, 0x0004, 0x007c, + 0x1078, 0x411c, 0x00c0, 0x29e2, 0x2011, 0x000c, 0x1078, 0x2a09, + 0x7003, 0x0004, 0x007c, 0x1078, 0x411c, 0x00c0, 0x29ed, 0x2011, + 0x0006, 0x1078, 0x2a09, 0x7003, 0x0004, 0x007c, 0x1078, 0x411c, + 0x00c0, 0x29f8, 0x2011, 0x000d, 0x1078, 0x2a09, 0x7003, 0x0004, + 0x007c, 0x1078, 0x411c, 0x00c0, 0x2a08, 0x2011, 0x0006, 0x1078, + 0x2a09, 0x707c, 0x707f, 0x0000, 0x2068, 0x704e, 0x7003, 0x0001, + 0x007c, 0x7174, 0xc1fc, 0x8107, 0x7882, 0x789b, 0x0010, 0xa286, + 0x000c, 0x00c0, 0x2a18, 0x7aaa, 0x2001, 0x0001, 0x0078, 0x2a2d, + 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286, 0x000d, 0x0040, + 0x2a26, 0x7aaa, 0x2001, 0x0002, 0x0078, 0x2a2d, 0x78ab, 0x0020, + 0x7178, 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b, 0x0060, 0x78aa, + 0x785b, 0x0004, 0x781b, 0x0108, 0x1078, 0x4131, 0x7083, 0x000f, + 0x70d4, 0xd0b4, 0x0040, 0x2a49, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x007c, 0x1078, 0x411c, 0x00c0, 0x2942, 0x707c, 0x2068, + 0x7774, 0x1078, 0x3fe1, 0x2c50, 0x1078, 0x41f0, 0x789b, 0x0010, + 0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, + 0x2001, 0x0004, 0x0078, 0x2bc3, 0x1078, 0x411c, 0x00c0, 0x2942, + 0x789b, 0x0010, 0x7060, 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0040, + 0x2a7e, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, + 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x1078, 0x3fe1, + 0x2c50, 0x1078, 0x41f0, 0x6824, 0xa005, 0x0040, 0x2a8f, 0xa082, + 0x0006, 0x0048, 0x2a8d, 0x0078, 0x2a8f, 0x6827, 0x0005, 0x6814, + 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, + 0x2001, 0x0003, 0x0078, 0x2bc3, 0xc28d, 0x72d6, 0x72c0, 0xa200, + 0xa015, 0x7154, 0x8108, 0xa12a, 0x0048, 0x2aa7, 0x71c0, 0x2164, + 0x6504, 0x85ff, 0x00c0, 0x2abe, 0x7156, 0x8421, 0x00c0, 0x2aa2, + 0x70d4, 0xd08c, 0x0040, 0x2aba, 0x70d0, 0xa005, 0x00c0, 0x2aba, + 0x70d3, 0x000a, 0x007c, 0x2200, 0x0078, 0x2aac, 0x70d4, 0xc08c, + 0x70d6, 0x70d3, 0x0000, 0x603c, 0xa005, 0x00c0, 0x2abb, 0x6708, + 0xa784, 0x073f, 0x0040, 0x2aed, 0xd7d4, 0x00c0, 0x2abb, 0xa784, + 0x0021, 0x00c0, 0x2abb, 0xa784, 0x0002, 0x0040, 0x2ade, 0xa784, + 0x0004, 0x0040, 0x2abb, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, + 0x00c0, 0x2abb, 0xa784, 0x0100, 0x0040, 0x2aed, 0x6018, 0xa005, + 0x00c0, 0x2abb, 0xa7bc, 0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, + 0x6e1c, 0xa684, 0x000e, 0x6318, 0x0040, 0x2afe, 0x601c, 0xa302, + 0x0048, 0x2b01, 0x0040, 0x2b01, 0x0078, 0x2abb, 0x83ff, 0x00c0, + 0x2abb, 0x2d58, 0x2c50, 0x7156, 0xd7bc, 0x00c0, 0x2b09, 0x7028, + 0x6022, 0xc7bc, 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, + 0x2041, 0x0001, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, + 0x0040, 0x2b1d, 0xd684, 0x0040, 0x2b1f, 0xa39c, 0xffbf, 0xd6a4, + 0x0040, 0x2b24, 0xa39d, 0x0020, 0xa684, 0x000e, 0x00c0, 0x2b6f, + 0xc7a5, 0x670a, 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, 0x00c0, + 0x2b43, 0x70d4, 0xd0b4, 0x00c0, 0x2b43, 0x7000, 0xa082, 0x0002, + 0x00c8, 0x2b43, 0x7830, 0xd0bc, 0x00c0, 0x2b43, 0x789b, 0x0010, + 0x7baa, 0x0078, 0x2bbb, 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, + 0x0005, 0x70ac, 0xa606, 0x00c0, 0x2b4e, 0x76a8, 0x76b2, 0x2c3a, + 0x8738, 0x2d3a, 0x8738, 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, + 0x7830, 0xd0bc, 0x0040, 0x2b66, 0x2091, 0x8000, 0x2091, 0x303d, + 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000, + 0x0040, 0x2b6e, 0x8421, 0x2200, 0x00c0, 0x2aa1, 0x007c, 0xd1dc, + 0x0040, 0x3be5, 0x2029, 0x0020, 0xd69c, 0x00c0, 0x2b7c, 0x8528, + 0xd68c, 0x00c0, 0x2b7c, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, + 0xa18c, 0x00ff, 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0040, 0x2b9b, + 0x6014, 0xa706, 0x00c0, 0x2b84, 0x60b8, 0x8001, 0x60ba, 0x00c0, + 0x2b7f, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, + 0x00c0, 0x2aa1, 0x007c, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, + 0x8840, 0x6008, 0xc0d5, 0x600a, 0x77a4, 0xa786, 0x0001, 0x00c0, + 0x2b43, 0x70d4, 0xd0b4, 0x00c0, 0x2b43, 0x7000, 0xa082, 0x0002, + 0x00c8, 0x2b43, 0x7830, 0xd0bc, 0x00c0, 0x2b43, 0x789b, 0x0010, + 0x7baa, 0x7daa, 0x79aa, 0x2001, 0x0002, 0x007e, 0x6018, 0x8000, + 0x601a, 0x0078, 0x2bc4, 0x007e, 0x2960, 0x6104, 0x2a60, 0xa184, + 0x0018, 0x0040, 0x2be0, 0xa184, 0x0010, 0x0040, 0x2bd3, 0x1078, + 0x3df6, 0x00c0, 0x2c05, 0xa184, 0x0008, 0x0040, 0x2be0, 0x69a0, + 0xa184, 0x0600, 0x00c0, 0x2be0, 0x1078, 0x3cda, 0x0078, 0x2c05, + 0x69a0, 0xa184, 0x1e00, 0x0040, 0x2c10, 0xa184, 0x0800, 0x0040, + 0x2bf9, 0x0c7e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, + 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x1078, 0x3df6, 0x00c0, 0x2c05, + 0x69a0, 0xa184, 0x0200, 0x0040, 0x2c01, 0x1078, 0x3d3a, 0x0078, + 0x2c05, 0xa184, 0x0400, 0x00c0, 0x2bdc, 0x69a0, 0xa184, 0x1000, + 0x0040, 0x2c10, 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x2749, + 0x027f, 0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x2c1d, 0xa086, + 0x0060, 0x00c0, 0x2c1d, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, + 0x789b, 0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, + 0x0040, 0x2c38, 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0050, + 0x2c36, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, + 0x78aa, 0x3518, 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, + 0x20a0, 0x789b, 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, + 0x2898, 0x25a0, 0xa286, 0x0020, 0x00c0, 0x2c70, 0x70d4, 0xc0b5, + 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, + 0x7882, 0xa286, 0x0002, 0x0040, 0x2ca6, 0x70a4, 0x8000, 0x70a6, + 0x74b4, 0xa498, 0x0005, 0x70ac, 0xa306, 0x00c0, 0x2c68, 0x73a8, + 0x73b6, 0xa286, 0x0010, 0x0040, 0x2942, 0x0d7f, 0x0c7f, 0x007c, + 0x7000, 0xa005, 0x00c0, 0x2c4e, 0xa286, 0x0002, 0x00c0, 0x2cc0, + 0x1078, 0x411c, 0x00c0, 0x2c4e, 0x6814, 0xc0fc, 0x8007, 0x7882, + 0x2091, 0x8000, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, + 0x780a, 0x127e, 0x0d7e, 0x0c7e, 0x70d4, 0xa084, 0x2700, 0x2090, + 0x0c7f, 0x0d7f, 0x127f, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, + 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x7830, 0xd0bc, + 0x0040, 0x2cb2, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, + 0x8000, 0x2090, 0x70a4, 0xa005, 0x00c0, 0x2cb7, 0x007c, 0x8421, + 0x0040, 0x2cb6, 0x7250, 0x70c0, 0xa200, 0xa015, 0x0078, 0x2aa1, + 0xa286, 0x0010, 0x00c0, 0x2cf1, 0x1078, 0x411c, 0x00c0, 0x2c4e, + 0x6814, 0xc0fc, 0x8007, 0x7882, 0x781b, 0x005b, 0x68b4, 0x785a, + 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, + 0x780a, 0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, + 0xa206, 0x00c0, 0x2ce4, 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, + 0x7042, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, + 0x007c, 0x6bb4, 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, + 0x7882, 0x6b94, 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, + 0x005b, 0x2900, 0x705a, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, + 0xa605, 0x0040, 0x2d1c, 0x70d4, 0xa084, 0x2700, 0xa086, 0x2300, + 0x00c0, 0x2d16, 0x2009, 0x0000, 0x0078, 0x2d18, 0x2009, 0x0001, + 0xa284, 0x000f, 0x1079, 0x2d20, 0xad80, 0x0009, 0x7046, 0x007c, + 0x2d28, 0x45f7, 0x45f7, 0x45e4, 0x45f7, 0x2d28, 0x2d28, 0x2d28, + 0x1078, 0x28ec, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e, 0x2079, + 0x4a00, 0x78ac, 0x0f7f, 0xd084, 0x0040, 0x2d4e, 0x7064, 0xa086, + 0x0001, 0x00c0, 0x2d3e, 0x7066, 0x0078, 0x2e27, 0x7064, 0xa086, + 0x0005, 0x00c0, 0x2d4c, 0x707c, 0x2068, 0x681b, 0x0004, 0x6817, + 0x0000, 0x6820, 0xc09d, 0x6822, 0x7067, 0x0000, 0x70a7, 0x0000, + 0x70a8, 0x70b2, 0x70b6, 0x70d4, 0xd0b4, 0x0040, 0x2d64, 0xc0b4, + 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x6018, 0x8001, 0x601a, 0x0c7f, 0x157e, 0x2011, 0x0004, 0x7164, + 0xa186, 0x0001, 0x0040, 0x2d7d, 0xa186, 0x0007, 0x00c0, 0x2d74, + 0x701f, 0x0005, 0x0078, 0x2d7d, 0x701f, 0x0001, 0x7067, 0x0000, + 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x2d7f, 0x7067, 0x0000, 0x2001, + 0x4a0a, 0x2004, 0xa084, 0x00ff, 0xa086, 0x0018, 0x0040, 0x2d8f, + 0x7018, 0x7016, 0xa005, 0x00c0, 0x2d8f, 0x70a7, 0x0001, 0x1078, + 0x4326, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078, 0x3edb, 0xa7b8, + 0x0100, 0x00f0, 0x2d95, 0x7000, 0x0079, 0x2d9e, 0x2dcd, 0x2db3, + 0x2db3, 0x2da8, 0x2dcd, 0x2dcd, 0x2dcd, 0x2da6, 0x1078, 0x28ec, + 0x7060, 0xa005, 0x0040, 0x2dcd, 0xad06, 0x00c0, 0x2db3, 0x6800, + 0x7062, 0x0078, 0x2dc5, 0x6820, 0xd084, 0x00c0, 0x2dc1, 0x6f14, + 0x1078, 0x3fe1, 0x6008, 0xc0d4, 0x600a, 0x1078, 0x3bb5, 0x0078, + 0x2dc5, 0x705c, 0x2060, 0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, + 0x6820, 0xc09d, 0x6822, 0x1078, 0x202a, 0xb284, 0x0400, 0x0040, + 0x2dd5, 0x2021, 0x91d0, 0x0078, 0x2dd7, 0x2021, 0x90c0, 0x1078, + 0x2e2c, 0xb284, 0x0400, 0x0040, 0x2de1, 0x2021, 0x4a98, 0x0078, + 0x2de3, 0x2021, 0x4a58, 0x1078, 0x2e2c, 0x20a9, 0x0101, 0xb284, + 0x0400, 0x0040, 0x2def, 0x2021, 0x90d0, 0x0078, 0x2df1, 0x2021, + 0x8fc0, 0x1078, 0x2e2c, 0x8420, 0x00f0, 0x2df1, 0xb284, 0x0300, + 0x0040, 0x2dfe, 0x2061, 0x4fc0, 0x0078, 0x2e00, 0x2061, 0x6fc0, + 0x2021, 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0040, 0x2e1d, + 0x6018, 0x017e, 0x007e, 0x2011, 0x4a02, 0x220c, 0xa102, 0x2012, + 0x007f, 0x017f, 0xa102, 0x0050, 0x2e1d, 0x6012, 0x00c0, 0x2e1d, + 0x2011, 0x4a04, 0x2204, 0xc0a5, 0x2012, 0x601b, 0x0000, 0xace0, + 0x0010, 0x00f0, 0x2e04, 0x8421, 0x00c0, 0x2e02, 0x157f, 0x7003, + 0x0000, 0x704f, 0x0000, 0x007c, 0x047e, 0x2404, 0xa005, 0x0040, + 0x2e3f, 0x2068, 0x6800, 0x007e, 0x6a1a, 0x6817, 0x0000, 0x6820, + 0xc09d, 0x6822, 0x1078, 0x202a, 0x007f, 0x0078, 0x2e2e, 0x047f, + 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, 0x0050, 0x2e49, 0x1078, + 0x28ec, 0x2300, 0x0079, 0x2e4c, 0x2e4f, 0x2eda, 0x2ef7, 0xa282, + 0x0002, 0x0040, 0x2e55, 0x1078, 0x28ec, 0x7064, 0x7067, 0x0000, + 0x7083, 0x0000, 0x0079, 0x2e5c, 0x2e64, 0x2e64, 0x2e66, 0x2ea6, + 0x3bf1, 0x2e64, 0x2ea6, 0x2e64, 0x1078, 0x28ec, 0x7774, 0x1078, + 0x3edb, 0x7774, 0xa7bc, 0x8f00, 0x1078, 0x3fe1, 0x6018, 0xa005, + 0x0040, 0x2e9d, 0xd7fc, 0x00c0, 0x2e79, 0x2021, 0x90c0, 0x0078, + 0x2e7b, 0x2021, 0x91d0, 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, + 0x2f12, 0x0040, 0x2e9d, 0x157e, 0x20a9, 0x0101, 0xd7fc, 0x00c0, + 0x2e8d, 0x2021, 0x8fc0, 0x0078, 0x2e8f, 0x2021, 0x90d0, 0x047e, + 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, 0x2f12, 0x047f, 0x0040, + 0x2e9c, 0x8420, 0x00f0, 0x2e8f, 0x157f, 0x8738, 0xa784, 0x001f, + 0x00c0, 0x2e6c, 0x0078, 0x2946, 0x0078, 0x2946, 0x7774, 0x1078, + 0x3fe1, 0x6018, 0xa005, 0x0040, 0x2ed8, 0xd7fc, 0x00c0, 0x2eb4, + 0x2021, 0x90c0, 0x0078, 0x2eb6, 0x2021, 0x91d0, 0x2009, 0x0005, + 0x2011, 0x0020, 0x1078, 0x2f12, 0x0040, 0x2ed8, 0x157e, 0x20a9, + 0x0101, 0xd7fc, 0x00c0, 0x2ec8, 0x2021, 0x8fc0, 0x0078, 0x2eca, + 0x2021, 0x90d0, 0x047e, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, + 0x2f12, 0x047f, 0x0040, 0x2ed7, 0x8420, 0x00f0, 0x2eca, 0x157f, + 0x0078, 0x2946, 0x2200, 0x0079, 0x2edd, 0x2ee0, 0x2ee2, 0x2ee2, + 0x1078, 0x28ec, 0x2009, 0x0012, 0x7064, 0xa086, 0x0002, 0x0040, + 0x2eeb, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0040, 0x2ef0, 0x691a, + 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x40c9, 0x2200, + 0x0079, 0x2efa, 0x2eff, 0x2ee2, 0x2efd, 0x1078, 0x28ec, 0x1078, + 0x4326, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3b7a, 0x1078, 0x3bd2, + 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3b6b, 0x0040, 0x3b7a, + 0x0078, 0x2946, 0x2404, 0xa005, 0x0040, 0x2f41, 0x2068, 0x2d04, + 0x007e, 0x6814, 0xa706, 0x0040, 0x2f21, 0x2d20, 0x007f, 0x0078, + 0x2f13, 0x007f, 0x2022, 0x691a, 0x6817, 0x0000, 0x6820, 0xa205, + 0x6822, 0x1078, 0x202a, 0x2021, 0x4a02, 0x241c, 0x8319, 0x2322, + 0x6010, 0x8001, 0x6012, 0x00c0, 0x2f3a, 0x2021, 0x4a04, 0x2404, + 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, 0x1078, 0x3bd2, + 0x007c, 0xa085, 0x0001, 0x0078, 0x2f40, 0x2300, 0x0079, 0x2f48, + 0x2f4d, 0x2f4b, 0x2fce, 0x1078, 0x28ec, 0x78e4, 0xa005, 0x00d0, + 0x2f84, 0x3208, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, + 0x0040, 0x2f5e, 0xa18c, 0x0300, 0x0078, 0x2f60, 0xa18c, 0x0400, + 0x0040, 0x2f66, 0x0018, 0x2942, 0x0078, 0x2f68, 0x0028, 0x2942, + 0x2008, 0xa084, 0x0030, 0x00c0, 0x2f70, 0x781b, 0x005b, 0x007c, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x2f6d, 0x2100, 0xa084, 0x0007, + 0x0079, 0x2f7a, 0x2fae, 0x2fb8, 0x2fa3, 0x2f82, 0x4111, 0x4111, + 0x2f82, 0x2fc3, 0x1078, 0x28ec, 0x7000, 0xa086, 0x0004, 0x00c0, + 0x2f9e, 0x7064, 0xa086, 0x0002, 0x00c0, 0x2f94, 0x2011, 0x0002, + 0x2019, 0x0000, 0x0078, 0x2e43, 0x7064, 0xa086, 0x0006, 0x0040, + 0x2f8e, 0x7064, 0xa086, 0x0004, 0x0040, 0x2f8e, 0x79e4, 0x2001, + 0x0003, 0x0078, 0x3304, 0x6818, 0xd0fc, 0x0040, 0x2fa9, 0x681b, + 0x001d, 0x1078, 0x3eae, 0x781b, 0x0061, 0x007c, 0x6818, 0xd0fc, + 0x0040, 0x2fb4, 0x681b, 0x001d, 0x1078, 0x3eae, 0x0078, 0x40ed, + 0x6818, 0xd0fc, 0x0040, 0x2fbe, 0x681b, 0x001d, 0x1078, 0x3eae, + 0x781b, 0x00ef, 0x007c, 0x6818, 0xd0fc, 0x0040, 0x2fc9, 0x681b, + 0x001d, 0x1078, 0x3eae, 0x781b, 0x00bf, 0x007c, 0xa584, 0x000f, + 0x00c0, 0x2feb, 0x7000, 0x0079, 0x2fd5, 0x2946, 0x2fdd, 0x2fdf, + 0x3b7a, 0x3b7a, 0x3b7a, 0x2fdd, 0x2fdd, 0x1078, 0x28ec, 0x1078, + 0x3bd2, 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3b6b, 0x0040, + 0x3b7a, 0x0078, 0x2946, 0x78e4, 0xa005, 0x00d0, 0x2f84, 0x3208, + 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2ffc, + 0xa18c, 0x0300, 0x0078, 0x2ffe, 0xa18c, 0x0400, 0x0040, 0x3004, + 0x0018, 0x2f84, 0x0078, 0x3006, 0x0028, 0x2f84, 0x2008, 0xa084, + 0x0030, 0x00c0, 0x300e, 0x781b, 0x005b, 0x007c, 0x78ec, 0xa084, + 0x0003, 0x0040, 0x300b, 0x2100, 0xa184, 0x0007, 0x0079, 0x3018, + 0x3027, 0x302b, 0x3022, 0x3020, 0x4111, 0x4111, 0x3020, 0x410b, + 0x1078, 0x28ec, 0x1078, 0x3eb6, 0x781b, 0x0061, 0x007c, 0x1078, + 0x3eb6, 0x0078, 0x40ed, 0x1078, 0x3eb6, 0x781b, 0x00ef, 0x007c, + 0x1078, 0x3eb6, 0x781b, 0x00bf, 0x007c, 0x2300, 0x0079, 0x3038, + 0x303d, 0x303b, 0x303f, 0x1078, 0x28ec, 0x0078, 0x37bd, 0x681b, + 0x0016, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x37bd, + 0x78ec, 0xa084, 0x0003, 0x0040, 0x37bd, 0xa184, 0x0100, 0x0040, + 0x3043, 0xa184, 0x0007, 0x0079, 0x3055, 0x305d, 0x302b, 0x2fa3, + 0x40c9, 0x4111, 0x4111, 0x40c9, 0x410b, 0x1078, 0x40d5, 0x007c, + 0xa282, 0x0005, 0x0050, 0x3066, 0x1078, 0x28ec, 0x2300, 0x0079, + 0x3069, 0x306c, 0x328b, 0x3296, 0x2200, 0x0079, 0x306f, 0x3089, + 0x3076, 0x3089, 0x3074, 0x326e, 0x1078, 0x28ec, 0x789b, 0x0018, + 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048, 0x3e9d, 0xa08a, + 0x0004, 0x00c8, 0x3e9d, 0x0079, 0x3085, 0x3e9d, 0x3e9d, 0x3e9d, + 0x3e47, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0040, 0x309a, + 0x0078, 0x3e9d, 0x7000, 0xa005, 0x00c0, 0x3090, 0x2011, 0x0004, + 0x0078, 0x3998, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8, 0x3e9d, + 0x0079, 0x30a2, 0x30b4, 0x30b2, 0x30c9, 0x30cd, 0x318f, 0x3e9d, + 0x3e9d, 0x3191, 0x3e9d, 0x3e9d, 0x326a, 0x326a, 0x3e9d, 0x3e9d, + 0x3e9d, 0x326c, 0x1078, 0x28ec, 0xd6e4, 0x0040, 0x30bf, 0x2001, + 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x00ba, 0x007c, 0x6818, + 0xd0fc, 0x0040, 0x30c7, 0x681b, 0x001d, 0x0078, 0x30b7, 0x0078, + 0x40c9, 0x681b, 0x001d, 0x0078, 0x3ea7, 0x6920, 0x6922, 0xa684, + 0x1800, 0x00c0, 0x3121, 0x6820, 0xd084, 0x00c0, 0x3127, 0x6818, + 0xa086, 0x0008, 0x00c0, 0x30de, 0x681b, 0x0000, 0xd6d4, 0x0040, + 0x318c, 0xd6bc, 0x0040, 0x311e, 0x7087, 0x0000, 0x6818, 0xa084, + 0x003f, 0xa08a, 0x000d, 0x0050, 0x311e, 0xa08a, 0x000c, 0x7186, + 0x2001, 0x000c, 0x800c, 0x718a, 0x789b, 0x0061, 0x78aa, 0x157e, + 0x137e, 0x147e, 0x017e, 0x3208, 0xa18c, 0x0300, 0x0040, 0x3110, + 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x310c, + 0x20a1, 0x012b, 0x0078, 0x3112, 0x20a1, 0x022b, 0x0078, 0x3112, + 0x20a1, 0x012b, 0x017f, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, + 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b, 0x0064, + 0x007c, 0xd6e4, 0x0040, 0x3127, 0x781b, 0x0076, 0x007c, 0xa684, + 0x0060, 0x0040, 0x3189, 0xd6dc, 0x0040, 0x3189, 0xd6fc, 0x00c0, + 0x3133, 0x0078, 0x314a, 0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, + 0x78d0, 0x801b, 0x00c8, 0x313d, 0x8000, 0xa084, 0x003f, 0xa108, + 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, + 0xa303, 0x68ae, 0xd6f4, 0x0040, 0x3150, 0xc6f4, 0x7e5a, 0x6eb6, + 0x7000, 0xa086, 0x0003, 0x00c0, 0x315e, 0x007e, 0x1078, 0x4326, + 0x1078, 0x45f7, 0x007f, 0x781b, 0x0073, 0x007c, 0xa006, 0x1078, + 0x46e5, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, + 0x316d, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, + 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x00c0, 0x317d, 0xc6f5, + 0x7e5a, 0x6eb6, 0x781b, 0x0073, 0x007c, 0x781b, 0x0073, 0x2200, + 0xa115, 0x00c0, 0x3186, 0x1078, 0x45f7, 0x007c, 0x1078, 0x462d, + 0x007c, 0x781b, 0x0076, 0x007c, 0x781b, 0x0064, 0x007c, 0x1078, + 0x28ec, 0x0078, 0x31dd, 0x6920, 0xd1c4, 0x0040, 0x31a6, 0xc1c4, + 0x6922, 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0e4, 0x6002, 0x6004, + 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x31d1, 0xd1cc, 0x0040, + 0x31d1, 0xc1cc, 0x6922, 0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0ec, + 0x6002, 0x6004, 0xc0a4, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xd19c, + 0x0040, 0x31d1, 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, + 0x31d1, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, + 0xd6d4, 0x00c0, 0x31ce, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, + 0x007c, 0x7e58, 0xd6d4, 0x00c0, 0x31d8, 0x781b, 0x0064, 0x007c, + 0x781b, 0x0076, 0x007c, 0x0078, 0x3ea2, 0x2019, 0x0000, 0x7990, + 0xa18c, 0x0007, 0x00c0, 0x31eb, 0x6820, 0xa084, 0x0100, 0x0040, + 0x31db, 0x2009, 0x0008, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, + 0xa286, 0x0001, 0x00c0, 0x3207, 0x2300, 0x7ca8, 0xa400, 0x2018, + 0xa102, 0x0040, 0x31ff, 0x0048, 0x31ff, 0x0078, 0x3201, 0x0078, + 0x3193, 0x24a8, 0x7aa8, 0x00f0, 0x3201, 0x0078, 0x31ed, 0xa284, + 0x00f0, 0xa086, 0x0020, 0x00c0, 0x325b, 0x8318, 0x8318, 0x2300, + 0xa102, 0x0040, 0x3217, 0x0048, 0x3217, 0x0078, 0x3258, 0xa286, + 0x0023, 0x0040, 0x31db, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, + 0xa684, 0xfff1, 0xc0a5, 0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, + 0x0c7e, 0x7058, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd1a4, + 0x0040, 0x3238, 0x1078, 0x3fdd, 0x1078, 0x3df6, 0x0078, 0x3246, + 0x0c7e, 0x7058, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd19c, + 0x0040, 0x31d1, 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, + 0x31d1, 0x789b, 0x0060, 0x2800, 0x78aa, 0xc695, 0x7e5a, 0xd6d4, + 0x00c0, 0x3255, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, 0x007c, + 0x7aa8, 0x0078, 0x31ed, 0x8318, 0x2300, 0xa102, 0x0040, 0x3264, + 0x0048, 0x3264, 0x0078, 0x31ed, 0xa284, 0x0080, 0x00c0, 0x3ea7, + 0x0078, 0x3ea2, 0x0078, 0x3ea7, 0x0078, 0x3e9d, 0x7058, 0xa04d, + 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001, 0x0040, + 0x327b, 0x1078, 0x28ec, 0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, + 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x3e9d, 0x0079, 0x3287, 0x3e9d, + 0x3c2c, 0x3e9d, 0x3d9e, 0xa282, 0x0000, 0x00c0, 0x3291, 0x1078, + 0x28ec, 0x1078, 0x3eae, 0x781b, 0x0075, 0x007c, 0xa282, 0x0003, + 0x00c0, 0x329c, 0x1078, 0x28ec, 0xd4fc, 0x00c0, 0x32bc, 0x7064, + 0xa005, 0x0040, 0x32a5, 0x1078, 0x28ec, 0x6f14, 0x7776, 0xa7bc, + 0x8f00, 0x1078, 0x3fe1, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, + 0xa784, 0x001f, 0x00c0, 0x32a9, 0x1078, 0x3eb2, 0x7067, 0x0002, + 0x701f, 0x0009, 0x0078, 0x32be, 0x1078, 0x3ebe, 0x781b, 0x0075, + 0x007c, 0xa282, 0x0004, 0x0050, 0x32c7, 0x1078, 0x28ec, 0x2300, + 0x0079, 0x32ca, 0x32cd, 0x346b, 0x34ae, 0xa286, 0x0003, 0x0040, + 0x3304, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x71d4, 0xd1b4, 0x0078, + 0x32fc, 0x0040, 0x32fc, 0x7868, 0xa084, 0x00ff, 0x00c0, 0x32fc, + 0xa282, 0x0002, 0x00c8, 0x32fc, 0x0d7e, 0x783b, 0x8300, 0x781b, + 0x004c, 0x70bc, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, + 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, + 0x2001, 0x0000, 0x0078, 0x3308, 0x783b, 0x1300, 0x781b, 0x004a, + 0x2001, 0x0000, 0x0078, 0x3308, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, + 0x704a, 0x68a0, 0xd0ec, 0x0040, 0x3310, 0x6008, 0xc08d, 0x600a, + 0xa284, 0x000f, 0x0079, 0x3314, 0x344b, 0x3321, 0x331e, 0x35ae, + 0x35f2, 0x2946, 0x331c, 0x331c, 0x1078, 0x28ec, 0x6008, 0xc0d4, + 0x600a, 0xd6e4, 0x00c0, 0x3328, 0x1078, 0x4326, 0x0040, 0x3404, + 0x7868, 0xa08c, 0x00ff, 0x0040, 0x3369, 0xa186, 0x0008, 0x00c0, + 0x333e, 0x1078, 0x3bd2, 0x6008, 0xc0a4, 0x600a, 0x1078, 0x3b6b, + 0x0040, 0x3369, 0x1078, 0x4326, 0x0078, 0x3353, 0xa186, 0x0028, + 0x00c0, 0x3369, 0x1078, 0x4326, 0x6008, 0xc0a4, 0x600a, 0x6018, + 0xa005, 0x0040, 0x3353, 0x8001, 0x601a, 0x0040, 0x3353, 0x8001, + 0x0040, 0x3353, 0x601e, 0x6820, 0xd084, 0x0040, 0x2946, 0xc084, + 0x6822, 0x705c, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, + 0x6802, 0xa005, 0x2d00, 0x00c0, 0x3366, 0x6002, 0x6006, 0x0078, + 0x2946, 0x017e, 0x81ff, 0x00c0, 0x33b0, 0x7000, 0xa086, 0x0030, + 0x0040, 0x33b0, 0x71d4, 0xd1b4, 0x00c0, 0x3397, 0x7060, 0xa005, + 0x00c0, 0x33b0, 0x70a4, 0xa086, 0x0001, 0x0040, 0x33b0, 0x7003, + 0x0000, 0x047e, 0x057e, 0x077e, 0x067e, 0x0c7e, 0x0d7e, 0x1078, + 0x296c, 0x0d7f, 0x0c7f, 0x067f, 0x077f, 0x057f, 0x047f, 0x71d4, + 0xd1b4, 0x00c0, 0x33b0, 0x7003, 0x0040, 0x0078, 0x33b0, 0x1078, + 0x411c, 0x00c0, 0x33b0, 0x781b, 0x005b, 0x0d7e, 0x70bc, 0xa06d, + 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, + 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x7808, 0xc08d, 0x780a, 0x0d7f, + 0x1078, 0x34e8, 0x017f, 0x81ff, 0x0040, 0x3403, 0xa684, 0xdf00, + 0x681e, 0x682b, 0x0000, 0x6f14, 0xa186, 0x0002, 0x00c0, 0x3404, + 0x70d4, 0xd0b4, 0x0040, 0x33d1, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x6820, 0xd0dc, 0x00c0, 0x3404, 0x8717, 0xa294, 0x000f, + 0x8213, 0x8213, 0x8213, 0xb284, 0x0300, 0x0040, 0x33e3, 0xa290, + 0x4ec0, 0x0078, 0x33e5, 0xa290, 0x4f40, 0xa290, 0x0000, 0x221c, + 0xd3c4, 0x00c0, 0x33ed, 0x0078, 0x33f3, 0x8210, 0x2204, 0xa085, + 0x0018, 0x2012, 0x8211, 0xd3d4, 0x0040, 0x33fe, 0x68a0, 0xd0c4, + 0x00c0, 0x33fe, 0x1078, 0x3562, 0x0078, 0x2946, 0x6008, 0xc08d, + 0x600a, 0x0078, 0x3404, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0040, + 0x340b, 0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, + 0x0040, 0x3420, 0x2009, 0x4a02, 0x2104, 0x8001, 0x200a, 0x8421, + 0x6412, 0x00c0, 0x3420, 0x2021, 0x4a04, 0x2404, 0xc0a5, 0x2022, + 0x6018, 0xa005, 0x0040, 0x3428, 0x8001, 0x601a, 0x00c0, 0x342b, + 0x6008, 0xc0a4, 0x600a, 0x6820, 0xd084, 0x00c0, 0x3437, 0x6800, + 0xa005, 0x00c0, 0x3434, 0x6002, 0x6006, 0x0078, 0x343b, 0x705c, + 0x2060, 0x6800, 0x6002, 0x2061, 0x4a00, 0x6887, 0x0103, 0x2d08, + 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x344a, 0x2d02, + 0x0078, 0x344b, 0x616e, 0x7200, 0xa286, 0x0030, 0x0040, 0x345b, + 0xa286, 0x0040, 0x00c0, 0x2946, 0x7003, 0x0002, 0x704c, 0x2068, + 0x68c4, 0x2060, 0x007c, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, + 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, + 0x0009, 0x7046, 0x007c, 0xa282, 0x0004, 0x0048, 0x3471, 0x1078, + 0x28ec, 0x2200, 0x0079, 0x3474, 0x3478, 0x3489, 0x3496, 0x3489, + 0xa586, 0x1300, 0x0040, 0x3489, 0xa586, 0x8300, 0x00c0, 0x346f, + 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x7000, 0xa086, 0x0005, 0x0040, 0x3493, 0x1078, 0x3eae, + 0x781b, 0x0075, 0x007c, 0x781b, 0x0076, 0x007c, 0x7890, 0x8007, + 0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, + 0x00ff, 0xa186, 0x0003, 0x0040, 0x34ab, 0xa186, 0x0000, 0x0040, + 0x34ab, 0x0078, 0x3e9d, 0x781b, 0x0076, 0x007c, 0x6820, 0xc095, + 0x6822, 0x82ff, 0x00c0, 0x34b8, 0x1078, 0x3eae, 0x0078, 0x34bf, + 0x8211, 0x0040, 0x34bd, 0x1078, 0x28ec, 0x1078, 0x3ebe, 0x781b, + 0x0075, 0x007c, 0x1078, 0x4131, 0x7830, 0xa084, 0x00c0, 0x00c0, + 0x34e5, 0x017e, 0x3208, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x34d7, 0xa18c, 0x0300, 0x0078, 0x34d9, 0xa18c, + 0x0400, 0x017f, 0x0040, 0x34e0, 0x0018, 0x34e5, 0x0078, 0x34e2, + 0x0028, 0x34e5, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, + 0xa684, 0x0060, 0x00c0, 0x34f2, 0x682f, 0x0000, 0x6833, 0x0000, + 0x0078, 0x3561, 0xd6dc, 0x00c0, 0x350a, 0x68b4, 0xd0dc, 0x00c0, + 0x350a, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, 0xa005, 0x00c0, + 0x3507, 0x2200, 0xa105, 0x0040, 0x4326, 0x704b, 0x0015, 0x0078, + 0x4326, 0x007c, 0xd6ac, 0x0040, 0x3530, 0xd6f4, 0x0040, 0x3516, + 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x4326, 0x68b4, 0xa084, + 0x4000, 0xa635, 0xd6f4, 0x00c0, 0x3510, 0x7048, 0xa005, 0x00c0, + 0x3523, 0x704b, 0x0015, 0xd6dc, 0x00c0, 0x352c, 0x68b4, 0xd0dc, + 0x0040, 0x352c, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0078, 0x4326, + 0xd6f4, 0x0040, 0x3539, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, + 0x4326, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x00c0, 0x3533, + 0x7048, 0xa005, 0x00c0, 0x3546, 0x704b, 0x0015, 0x2408, 0x2510, + 0x2700, 0x80fb, 0x00c8, 0x354d, 0x8000, 0xa084, 0x003f, 0xa108, + 0xa291, 0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, 0x00c0, 0x355a, + 0x0078, 0x4326, 0x7000, 0xa086, 0x0006, 0x0040, 0x3561, 0x0078, + 0x4326, 0x007c, 0x6008, 0xc0cd, 0xd3cc, 0x0040, 0x3568, 0xc08d, + 0x600a, 0x681b, 0x0006, 0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, + 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833, 0x0000, 0x6837, + 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, 0x7000, 0x0079, 0x3580, + 0x2946, 0x3592, 0x358a, 0x3588, 0x3588, 0x3588, 0x3588, 0x3588, + 0x1078, 0x28ec, 0x6820, 0xd084, 0x00c0, 0x3592, 0x1078, 0x3bb5, + 0x0078, 0x3598, 0x705c, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, + 0x3208, 0xa18c, 0x0300, 0x0040, 0x35a1, 0x2021, 0x4a58, 0x0078, + 0x35a3, 0x2021, 0x4a98, 0x2404, 0xa005, 0x0040, 0x35aa, 0x2020, + 0x0078, 0x35a3, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, 0x3bbc, + 0x1078, 0x3bd2, 0x6008, 0xc0cc, 0x600a, 0x682b, 0x0000, 0x789b, + 0x000e, 0x6f14, 0x6817, 0x0002, 0x3208, 0xa18c, 0x0300, 0x0040, + 0x35c5, 0x2009, 0x0000, 0x0078, 0x35c7, 0x2009, 0x0001, 0x1078, + 0x471a, 0xd6dc, 0x0040, 0x35cf, 0x691c, 0xc1ed, 0x691e, 0x6818, + 0xd0fc, 0x0040, 0x35de, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x35dc, + 0x681b, 0x001e, 0x0078, 0x35de, 0x681b, 0x0000, 0xb284, 0x0300, + 0x00c0, 0x35e6, 0x2021, 0x4a98, 0x0078, 0x35e8, 0x2021, 0x4a58, + 0x6800, 0x2022, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x202a, + 0x0078, 0x2946, 0x7cd8, 0x7ddc, 0x7fd0, 0x1078, 0x34e8, 0x682b, + 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078, 0x4135, 0xa08c, 0x00ff, + 0x6916, 0x6818, 0xd0fc, 0x0040, 0x3607, 0x7048, 0x681a, 0xa68c, + 0xdf00, 0x691e, 0x7067, 0x0000, 0x0078, 0x2946, 0x7000, 0xa005, + 0x00c0, 0x3614, 0x0078, 0x2946, 0xa006, 0x1078, 0x4326, 0x6817, + 0x0000, 0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, + 0x6820, 0xa084, 0x00ff, 0x6822, 0x7000, 0x0079, 0x3627, 0x2946, + 0x3634, 0x3631, 0x3636, 0x3636, 0x3636, 0x362f, 0x362f, 0x1078, + 0x28ec, 0x6008, 0xc0d4, 0x600a, 0x1078, 0x3bd2, 0x6008, 0xc0a4, + 0x600a, 0x0078, 0x3b85, 0x2300, 0x0079, 0x363e, 0x3641, 0x3643, + 0x369f, 0x1078, 0x28ec, 0xd6fc, 0x00c0, 0x3686, 0x7000, 0xa00d, + 0x0079, 0x364a, 0x2946, 0x3654, 0x3654, 0x3678, 0x3654, 0x3683, + 0x3652, 0x3652, 0x1078, 0x28ec, 0xa684, 0x0060, 0xa086, 0x0060, + 0x00c0, 0x3675, 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x681c, 0xc0ac, + 0x681e, 0xa186, 0x0002, 0x0040, 0x3667, 0x1078, 0x4326, 0x1078, + 0x45f7, 0x781b, 0x0076, 0x71d4, 0xd1b4, 0x00c0, 0x2942, 0x70a4, + 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6ec, 0x0040, 0x365c, + 0x6818, 0xd0fc, 0x0040, 0x3683, 0x681b, 0x0015, 0xd6f4, 0x0040, + 0x3683, 0x681b, 0x0007, 0x1078, 0x40d5, 0x007c, 0xc6fc, 0x7e5a, + 0x7adc, 0x79d8, 0x78d0, 0x801b, 0x00c8, 0x368f, 0x8000, 0xa084, + 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, + 0x6b94, 0x2200, 0xa303, 0x68ae, 0x781b, 0x0076, 0x007c, 0x1078, + 0x28ec, 0x2300, 0x0079, 0x36a4, 0x36a9, 0x36c5, 0x3719, 0x1078, + 0x28ec, 0x7000, 0x0079, 0x36ac, 0x36b4, 0x36b6, 0x36b6, 0x36b4, + 0x36b4, 0x36b4, 0x36b4, 0x36b4, 0x1078, 0x28ec, 0x1078, 0x45f7, + 0x681c, 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x00c0, 0x2942, 0x70a4, + 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6fc, 0x00c0, 0x3709, + 0x7000, 0xa00d, 0x0079, 0x36cc, 0x2946, 0x36dc, 0x36d6, 0x3700, + 0x36dc, 0x3706, 0x36d4, 0x36d4, 0x1078, 0x28ec, 0x6894, 0x78d6, + 0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, 0xa086, 0x0060, + 0x00c0, 0x36fd, 0xa6b4, 0xbfbf, 0xc6ed, 0x7e5a, 0xa186, 0x0002, + 0x0040, 0x36ec, 0x1078, 0x4326, 0x1078, 0x45f7, 0x781b, 0x0076, + 0x681c, 0xc0b4, 0x681e, 0x71d4, 0xd1b4, 0x00c0, 0x2942, 0x70a4, + 0xa086, 0x0001, 0x00c0, 0x2989, 0x007c, 0xd6ec, 0x0040, 0x36e4, + 0x6818, 0xd0fc, 0x0040, 0x3706, 0x681b, 0x0007, 0x781b, 0x00f0, + 0x007c, 0xc6fc, 0x7e5a, 0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, + 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x79d2, 0x781b, 0x0076, + 0x007c, 0xd6dc, 0x0040, 0x3722, 0x782b, 0x3009, 0x781b, 0x0076, + 0x0078, 0x2942, 0x7884, 0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, + 0x00c0, 0x3735, 0xa484, 0x0200, 0x0040, 0x372f, 0xc6f5, 0xc6dd, + 0x7e5a, 0x781b, 0x0076, 0x0078, 0x2942, 0x6820, 0xc095, 0x6822, + 0x1078, 0x4062, 0xc6dd, 0x1078, 0x3eae, 0x781b, 0x0075, 0x0078, + 0x2942, 0x2300, 0x0079, 0x3744, 0x3747, 0x3749, 0x374b, 0x1078, + 0x28ec, 0x0078, 0x3ea7, 0xd6d4, 0x00c0, 0x3771, 0x79e4, 0xd1ac, + 0x0040, 0x3759, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3759, 0x782b, + 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, + 0x79e4, 0xd1ac, 0x0040, 0x3769, 0x78ec, 0xa084, 0x0003, 0x00c0, + 0x376d, 0x2001, 0x0014, 0x0078, 0x3304, 0xa184, 0x0007, 0x0079, + 0x37a7, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, + 0x0040, 0x37a5, 0x789b, 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, + 0x3798, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, 0x378b, 0x2009, + 0xfff7, 0x0078, 0x3791, 0xa386, 0x0003, 0x00c0, 0x3798, 0x2009, + 0xffef, 0x0c7e, 0x7058, 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, + 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, + 0x3009, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40c9, 0x2fae, + 0x2fb8, 0x37b1, 0x37b7, 0x37af, 0x37af, 0x40c9, 0x40c9, 0x1078, + 0x28ec, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40cf, 0x6920, + 0xa18c, 0xfcff, 0x6922, 0x0078, 0x40c9, 0x79e4, 0xa184, 0x0030, + 0x0040, 0x37c7, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x37f1, 0x7000, + 0xa086, 0x0004, 0x00c0, 0x37e1, 0x7064, 0xa086, 0x0002, 0x00c0, + 0x37d7, 0x2011, 0x0002, 0x2019, 0x0000, 0x0078, 0x2e43, 0x7064, + 0xa086, 0x0006, 0x0040, 0x37d1, 0x7064, 0xa086, 0x0004, 0x0040, + 0x37d1, 0x7000, 0xa086, 0x0000, 0x0040, 0x2942, 0x6820, 0xd0ac, + 0x00c0, 0x37ed, 0x6818, 0xc0fd, 0x681a, 0x2001, 0x0014, 0x0078, + 0x3304, 0xa184, 0x0007, 0x0079, 0x37f5, 0x40c9, 0x40c9, 0x37fd, + 0x40c9, 0x4111, 0x4111, 0x40c9, 0x40c9, 0xd6bc, 0x0040, 0x383f, + 0x7184, 0x81ff, 0x0040, 0x383f, 0xa182, 0x000d, 0x00d0, 0x380c, + 0x7087, 0x0000, 0x0078, 0x3811, 0xa182, 0x000c, 0x7086, 0x2009, + 0x000c, 0x789b, 0x0061, 0x79aa, 0x157e, 0x137e, 0x147e, 0x7088, + 0x8114, 0xa210, 0x728a, 0xa080, 0x000b, 0xad00, 0x2098, 0xb284, + 0x0300, 0x0040, 0x3833, 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, + 0x007f, 0x0040, 0x382f, 0x20a1, 0x012b, 0x0078, 0x3835, 0x20a1, + 0x022b, 0x0078, 0x3835, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, + 0x81ac, 0x53a6, 0x147f, 0x137f, 0x157f, 0x0078, 0x40cf, 0xd6d4, + 0x00c0, 0x3893, 0x6820, 0xd084, 0x0040, 0x40cf, 0xa68c, 0x0060, + 0xa684, 0x0060, 0x0040, 0x3851, 0xa086, 0x0060, 0x00c0, 0x3851, + 0xc1f5, 0xc194, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000, + 0x789b, 0x0061, 0x6818, 0xc0fd, 0x681a, 0x78aa, 0x8008, 0x810c, + 0x0040, 0x3beb, 0xa18c, 0x00f8, 0x00c0, 0x3beb, 0x157e, 0x137e, + 0x147e, 0x017e, 0x3208, 0xa18c, 0x0300, 0x0040, 0x387f, 0x007e, + 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x387b, 0x20a1, + 0x012b, 0x0078, 0x3881, 0x20a1, 0x022b, 0x0078, 0x3881, 0x20a1, + 0x012b, 0x017f, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, + 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814, 0xc0fc, 0x8007, + 0x7882, 0x0078, 0x40cf, 0x6818, 0xd0fc, 0x0040, 0x3899, 0x681b, + 0x0008, 0x6820, 0xc0ad, 0x6822, 0x1078, 0x3eb6, 0x781b, 0x00e1, + 0x007c, 0x2300, 0x0079, 0x38a4, 0x38a9, 0x397b, 0x38a7, 0x1078, + 0x28ec, 0x7cd8, 0x7ddc, 0x7fd0, 0x82ff, 0x00c0, 0x38d1, 0x7200, + 0xa286, 0x0003, 0x0040, 0x32d2, 0x71d4, 0xd1b4, 0x0078, 0x38d4, + 0x0040, 0x38d4, 0x0d7e, 0x783b, 0x8800, 0x781b, 0x004c, 0x70bc, + 0xa06d, 0x68b4, 0xc0a5, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, + 0x78d2, 0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x0078, + 0x38d8, 0x7200, 0x0078, 0x38d8, 0x783b, 0x1800, 0x781b, 0x004a, + 0xa284, 0x000f, 0x0079, 0x38dc, 0x3966, 0x391a, 0x38e6, 0x3300, + 0x38e4, 0x3966, 0x38e4, 0x38e4, 0x1078, 0x28ec, 0x681c, 0xd0ec, + 0x0040, 0x38ed, 0x6008, 0xc08d, 0x600a, 0x6920, 0xc185, 0x6922, + 0x6800, 0x6006, 0xa005, 0x00c0, 0x38f6, 0x6002, 0x6008, 0xc0d4, + 0x600a, 0x681c, 0xa084, 0x000e, 0x00c0, 0x390a, 0xb284, 0x0300, + 0x0040, 0x3906, 0x2009, 0x90c0, 0x0078, 0x390f, 0x2009, 0x91d0, + 0x0078, 0x390f, 0x7030, 0x68ba, 0x7140, 0x70cc, 0xa108, 0x2104, + 0x6802, 0x2d0a, 0x715e, 0xd6dc, 0x00c0, 0x391a, 0xc6fc, 0x6eb6, + 0x0078, 0x3966, 0x6eb6, 0xa684, 0x0060, 0x0040, 0x3966, 0xd6dc, + 0x00c0, 0x392d, 0xa684, 0x7fff, 0x68b6, 0x6894, 0x68a6, 0x6898, + 0x68aa, 0x1078, 0x4326, 0x0078, 0x3966, 0xd6ac, 0x0040, 0x3939, + 0xa006, 0x1078, 0x4326, 0x2408, 0x2510, 0x69aa, 0x6aa6, 0x0078, + 0x3949, 0x2408, 0x2510, 0x2700, 0x801b, 0x00c8, 0x3940, 0x8000, + 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x69aa, 0x6aa6, 0x1078, + 0x4326, 0xd6fc, 0x0040, 0x3966, 0xa684, 0x7fff, 0x68b6, 0x2510, + 0x2408, 0xd6ac, 0x00c0, 0x395e, 0x2700, 0x801b, 0x00c8, 0x3959, + 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, + 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x7000, 0xa086, + 0x0030, 0x00c0, 0x2946, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, + 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, + 0x0009, 0x7046, 0x007c, 0xa586, 0x8800, 0x00c0, 0x3988, 0x7003, + 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x0078, 0x3ea7, 0x7047, 0x0000, 0xa282, 0x0006, 0x0050, 0x3992, + 0x1078, 0x28ec, 0x2300, 0x0079, 0x3995, 0x3998, 0x39cf, 0x3a01, + 0x2200, 0x0079, 0x399b, 0x39a1, 0x3ea7, 0x39a3, 0x39a1, 0x3a38, + 0x3a9b, 0x1078, 0x28ec, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, + 0x39ad, 0x2001, 0x91e0, 0x0078, 0x39af, 0x2001, 0x9212, 0x2068, + 0x704e, 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, + 0x39b4, 0x157f, 0xb284, 0x0300, 0x0040, 0x39c2, 0x6817, 0x0000, + 0x0078, 0x39c4, 0x6817, 0x8000, 0xad80, 0x0009, 0x7046, 0x68b7, + 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x0078, 0x3e9d, 0x7000, + 0xa086, 0x0002, 0x00c0, 0x39e0, 0x1078, 0x3bd2, 0x0078, 0x39da, + 0x1078, 0x4326, 0x6008, 0xa084, 0xfbef, 0x600a, 0x0078, 0x39e5, + 0x7000, 0xa086, 0x0003, 0x0040, 0x39d8, 0x7003, 0x0005, 0xb284, + 0x0300, 0x0040, 0x39ef, 0x2001, 0x91e0, 0x0078, 0x39f1, 0x2001, + 0x9212, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, 0x2200, 0x0079, + 0x39f9, 0x3ea7, 0x39ff, 0x39ff, 0x3a38, 0x39ff, 0x3ea7, 0x1078, + 0x28ec, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3a12, 0x1078, 0x3bd2, + 0x0078, 0x3a0c, 0x1078, 0x4326, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x0078, 0x3a17, 0x7000, 0xa086, 0x0003, 0x0040, 0x3a0a, 0x7003, + 0x0005, 0xb284, 0x0300, 0x0040, 0x3a21, 0x2001, 0x91e0, 0x0078, + 0x3a23, 0x2001, 0x9212, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046, + 0x2200, 0x0079, 0x3a2b, 0x3a33, 0x3a31, 0x3a31, 0x3a33, 0x3a31, + 0x3a33, 0x1078, 0x28ec, 0x1078, 0x3ebe, 0x781b, 0x0075, 0x007c, + 0x7000, 0xa086, 0x0002, 0x00c0, 0x3a4a, 0x70d4, 0xc0b5, 0x70d6, + 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3a4f, 0x1078, 0x4326, + 0x0078, 0x3a4f, 0x7000, 0xa086, 0x0003, 0x0040, 0x3a46, 0x7003, + 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, + 0x001f, 0xa215, 0x2069, 0x90c0, 0xb284, 0x0300, 0x00c0, 0x3a63, + 0xc2fd, 0x2069, 0x91d0, 0x2d04, 0x2d08, 0x715e, 0xa06d, 0x0040, + 0x3a70, 0x6814, 0xa206, 0x0040, 0x3a90, 0x6800, 0x0078, 0x3a64, + 0x7003, 0x0005, 0xd2fc, 0x00c0, 0x3a79, 0x2001, 0x91e0, 0x0078, + 0x3a7b, 0x2001, 0x9212, 0x2068, 0x704e, 0x157e, 0x20a9, 0x0032, + 0x2003, 0x0000, 0x8000, 0x00f0, 0x3a80, 0x157f, 0xad80, 0x0009, + 0x7046, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, + 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x3b10, 0x1078, + 0x3eb6, 0x0078, 0x3b10, 0x7200, 0xa286, 0x0002, 0x00c0, 0x3aad, + 0x70d4, 0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, + 0x3ab1, 0x1078, 0x4326, 0x0078, 0x3ab1, 0xa286, 0x0003, 0x0040, + 0x3aa9, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, + 0x7ca8, 0xa484, 0x001f, 0xa215, 0xb284, 0x0300, 0x00c0, 0x3ac1, + 0xc2fd, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0x70cc, 0xa168, 0x2d04, + 0x2d08, 0x715e, 0xa06d, 0x0040, 0x3ad4, 0x6814, 0xa206, 0x0040, + 0x3afd, 0x6800, 0x0078, 0x3ac8, 0x7003, 0x0005, 0xb284, 0x0300, + 0x0040, 0x3ade, 0x2001, 0x91e0, 0x0078, 0x3ae0, 0x2001, 0x9212, + 0x2068, 0x704e, 0x157e, 0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, + 0x00f0, 0x3ae5, 0x157f, 0xb284, 0x0300, 0x0040, 0x3af2, 0xc2fc, + 0x0078, 0x3af3, 0xc2fd, 0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, + 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x6820, 0xa084, + 0x0c00, 0x0040, 0x3b10, 0xd0dc, 0x0040, 0x3b0a, 0x1078, 0x3eba, + 0x0078, 0x3b10, 0x1078, 0x3eb6, 0x707f, 0x0000, 0x0078, 0x3b10, + 0xa6ac, 0x0060, 0x0040, 0x3b4e, 0x6b98, 0x6c94, 0x69ac, 0x68b0, + 0xa105, 0x00c0, 0x3b33, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, + 0xb7ff, 0xa586, 0x0060, 0x0040, 0x3b4e, 0xc6ed, 0x7e5a, 0x2009, + 0x0076, 0xd69c, 0x0040, 0x3b2e, 0x2009, 0x0075, 0x791a, 0x1078, + 0x45f7, 0x0078, 0x3b57, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, + 0xa305, 0x0040, 0x3b4e, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, + 0xc6f4, 0x7e5a, 0x2011, 0x0076, 0xd69c, 0x0040, 0x3b49, 0x2011, + 0x0075, 0x7a1a, 0x1078, 0x462d, 0x0078, 0x3b57, 0x7e5a, 0x2009, + 0x0076, 0xd69c, 0x0040, 0x3b56, 0x2009, 0x0075, 0x791a, 0x68c0, + 0x705a, 0x2d00, 0x704e, 0x68c4, 0x2060, 0x71d4, 0xd1b4, 0x00c0, + 0x2942, 0x2300, 0xa405, 0x0040, 0x2942, 0x70a4, 0xa086, 0x0001, + 0x00c0, 0x2989, 0x007c, 0x6020, 0xa005, 0x0040, 0x3b79, 0x8001, + 0x6022, 0x6008, 0xa085, 0x0008, 0x600a, 0x700f, 0x0100, 0x702c, + 0x6026, 0x007c, 0xa006, 0x1078, 0x4326, 0x6817, 0x0000, 0x681b, + 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x000f, + 0x0079, 0x3b8a, 0x2946, 0x3b94, 0x3b94, 0x3bb1, 0x3b9c, 0x2946, + 0x3b92, 0x3b92, 0x1078, 0x28ec, 0x1078, 0x3bbc, 0x1078, 0x3bb5, + 0x1078, 0x202a, 0x0078, 0x2946, 0x7064, 0x7067, 0x0000, 0x7083, + 0x0000, 0x0079, 0x3ba3, 0x3bad, 0x3bad, 0x3bab, 0x3bab, 0x3bab, + 0x3bad, 0x3bab, 0x3bad, 0x0079, 0x2e5c, 0x7067, 0x0000, 0x0078, + 0x2946, 0x681b, 0x0000, 0x0078, 0x35ae, 0x6800, 0xa005, 0x00c0, + 0x3bba, 0x6002, 0x6006, 0x007c, 0x6410, 0x84ff, 0x0040, 0x3bce, + 0x2009, 0x4a02, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, 0x00c0, + 0x3bce, 0x2021, 0x4a04, 0x2404, 0xc0a5, 0x2022, 0x6008, 0xc0a4, + 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x3bd8, 0x8001, 0x601a, + 0x007c, 0x1078, 0x4131, 0x681b, 0x0018, 0x0078, 0x3c1a, 0x1078, + 0x4131, 0x681b, 0x0019, 0x0078, 0x3c1a, 0x1078, 0x4131, 0x681b, + 0x001a, 0x0078, 0x3c1a, 0x1078, 0x4131, 0x681b, 0x0003, 0x0078, + 0x3c1a, 0x7774, 0x1078, 0x3fe1, 0x7178, 0xa18c, 0x00ff, 0x3210, + 0xa294, 0x0300, 0x0040, 0x3c00, 0xa1e8, 0x8fc0, 0x0078, 0x3c02, + 0xa1e8, 0x90d0, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, 0x3c0a, + 0x0078, 0x2946, 0x6814, 0xc0fc, 0x7274, 0xc2fc, 0xa206, 0x0040, + 0x3c14, 0x6800, 0x0078, 0x3c03, 0x6800, 0x200a, 0x681b, 0x0005, + 0x707f, 0x0000, 0x1078, 0x3bbc, 0x6820, 0xd084, 0x00c0, 0x3c22, + 0x1078, 0x3bb5, 0x1078, 0x3bd2, 0x681f, 0x0000, 0x6823, 0x0020, + 0x1078, 0x202a, 0x0078, 0x2946, 0xa282, 0x0003, 0x00c0, 0x3e9d, + 0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, 0xc1bd, + 0x6922, 0xd1c4, 0x0040, 0x3c86, 0xc1c4, 0x6922, 0xa6b4, 0x00ff, + 0x0040, 0x3c73, 0xa682, 0x000c, 0x0048, 0x3c4a, 0x0040, 0x3c4a, + 0x2031, 0x000c, 0x2500, 0xa086, 0x000a, 0x0040, 0x3c51, 0x852b, + 0x852b, 0x1078, 0x3f73, 0x0040, 0x3c59, 0x1078, 0x3d55, 0x0078, + 0x3c7c, 0x1078, 0x3f2e, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, + 0x6006, 0x1078, 0x3d8a, 0x0c7f, 0x6920, 0xc1c5, 0x6922, 0x7e58, + 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x3c70, 0x781b, 0x0061, 0x007c, + 0x781b, 0x0075, 0x007c, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, + 0x6006, 0x1078, 0x3d8a, 0x0c7f, 0x7e58, 0xd6d4, 0x00c0, 0x3c83, + 0x781b, 0x0064, 0x007c, 0x781b, 0x0076, 0x007c, 0x0c7e, 0x7058, + 0x2060, 0x6100, 0xd1e4, 0x0040, 0x3ccf, 0x6208, 0x8217, 0xa294, + 0x00ff, 0xa282, 0x000c, 0x0048, 0x3c99, 0x0040, 0x3c99, 0x2011, + 0x000c, 0x2600, 0xa202, 0x00c8, 0x3c9e, 0x2230, 0x6208, 0xa294, + 0x00ff, 0x2001, 0x4a05, 0x2004, 0xd0e4, 0x00c0, 0x3cb3, 0x78ec, + 0xd0e4, 0x0040, 0x3cb3, 0xa282, 0x000a, 0x00c8, 0x3cb9, 0x2011, + 0x000a, 0x0078, 0x3cb9, 0xa282, 0x000c, 0x00c8, 0x3cb9, 0x2011, + 0x000c, 0x2200, 0xa502, 0x00c8, 0x3cbe, 0x2228, 0x1078, 0x3f32, + 0x2500, 0xa086, 0x000a, 0x0040, 0x3cc7, 0x852b, 0x852b, 0x1078, + 0x3f73, 0x0040, 0x3ccf, 0x1078, 0x3d55, 0x0078, 0x3cd3, 0x1078, + 0x3f2e, 0x1078, 0x3d8a, 0x7858, 0xc095, 0x785a, 0x0c7f, 0x781b, + 0x0075, 0x007c, 0x0c7e, 0x2960, 0x6000, 0xd0e4, 0x00c0, 0x3cf1, + 0x6010, 0xa084, 0x000f, 0x00c0, 0x3ceb, 0x6104, 0xa18c, 0xfff5, + 0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, + 0x3d1c, 0x68a0, 0xd0cc, 0x00c0, 0x3ceb, 0x6208, 0xa294, 0x00ff, + 0x2001, 0x4a05, 0x2004, 0xd0e4, 0x00c0, 0x3d0a, 0x78ec, 0xd0e4, + 0x0040, 0x3d0a, 0xa282, 0x000a, 0x00c0, 0x3d0a, 0x2011, 0x000a, + 0x0078, 0x3d10, 0xa282, 0x000c, 0x00c8, 0x3d10, 0x2011, 0x000c, + 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c, 0x0048, 0x3d1c, + 0x0040, 0x3d1c, 0x2019, 0x000c, 0x78ab, 0x0001, 0x78ab, 0x0003, + 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, + 0x6822, 0x70d4, 0xd0b4, 0x0040, 0x3d38, 0xc0b4, 0x70d6, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x007c, 0x0c7e, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106, + 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3d46, 0x78ab, 0x0001, + 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, + 0x6820, 0xc0c5, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7158, 0x2160, + 0x2018, 0xa08c, 0x0020, 0x0040, 0x3d5e, 0xc0ac, 0x2008, 0xa084, + 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, + 0xa084, 0xfff0, 0xa18c, 0x000f, 0xa105, 0xa39c, 0x0020, 0x0040, + 0x3d73, 0xa085, 0x4000, 0xc0fc, 0xd0b4, 0x00c0, 0x3d78, 0xc0fd, + 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, + 0xa084, 0x00ff, 0xa605, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, + 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x6018, 0x789a, 0x78a4, + 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, + 0x600c, 0xa084, 0x00ff, 0x600e, 0x0c7f, 0x007c, 0xa282, 0x0002, + 0x00c0, 0x3e9d, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc, 0x0040, + 0x3dd9, 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, + 0x3e9d, 0x1078, 0x3e2a, 0x1078, 0x3d8a, 0xa980, 0x0001, 0x200c, + 0x1078, 0x3fdd, 0x1078, 0x3cda, 0x88ff, 0x0040, 0x3dcf, 0x789b, + 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, + 0x3dcc, 0x781b, 0x0061, 0x007c, 0x781b, 0x0075, 0x007c, 0x7e58, + 0xd6d4, 0x00c0, 0x3dd6, 0x781b, 0x0064, 0x007c, 0x781b, 0x0076, + 0x007c, 0xa282, 0x0002, 0x00c8, 0x3de1, 0xa284, 0x0001, 0x0040, + 0x3dea, 0x7158, 0xa188, 0x0000, 0x210c, 0xd1ec, 0x00c0, 0x3dea, + 0x2011, 0x0000, 0x1078, 0x3f0f, 0x1078, 0x3e2a, 0x1078, 0x3d8a, + 0x7858, 0xc095, 0x785a, 0x781b, 0x0075, 0x007c, 0x0c7e, 0x027e, + 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x00c0, 0x3e0b, 0x6014, + 0xa084, 0x0040, 0x00c0, 0x3e09, 0xc1a4, 0x6106, 0xa006, 0x0078, + 0x3e27, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, + 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x70d4, 0xd0b4, 0x0040, 0x3e23, + 0xc0b4, 0x70d6, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, + 0x6018, 0x8001, 0x601a, 0x6820, 0xa085, 0x0200, 0x6822, 0x027f, + 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x82ff, 0x0040, 0x3e32, + 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, + 0xffbf, 0xa205, 0xc0fc, 0xd0b4, 0x00c0, 0x3e3f, 0xc0fd, 0x78a6, + 0x6016, 0x788a, 0x6004, 0xc0a4, 0x6006, 0x0c7f, 0x007c, 0x007e, + 0x7000, 0xa086, 0x0003, 0x0040, 0x3e50, 0x007f, 0x0078, 0x3e53, + 0x007f, 0x0078, 0x3e9a, 0xd6ac, 0x0040, 0x3e9a, 0x7888, 0xa084, + 0x0040, 0x0040, 0x3e9a, 0x7bb8, 0xa384, 0x003f, 0x831b, 0x00c8, + 0x3e62, 0x8000, 0xa005, 0x0040, 0x3e77, 0x831b, 0x00c8, 0x3e6b, + 0x8001, 0x0040, 0x3e97, 0xd6f4, 0x0040, 0x3e77, 0x78b8, 0x801b, + 0x00c8, 0x3e73, 0x8000, 0xa084, 0x003f, 0x00c0, 0x3e97, 0xc6f4, + 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, 0x3e82, + 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x46e5, + 0x781b, 0x0073, 0xb284, 0x0300, 0x0040, 0x3e92, 0x2001, 0x0000, + 0x0078, 0x3e94, 0x2001, 0x0001, 0x1078, 0x4585, 0x007c, 0x781b, + 0x0073, 0x007c, 0x781b, 0x0076, 0x007c, 0x1078, 0x3ec2, 0x781b, + 0x0075, 0x007c, 0x1078, 0x3eae, 0x781b, 0x0075, 0x007c, 0x6827, + 0x0002, 0x1078, 0x3eb6, 0x781b, 0x0075, 0x007c, 0x2001, 0x0005, + 0x0078, 0x3ec4, 0x2001, 0x000c, 0x0078, 0x3ec4, 0x2001, 0x0006, + 0x0078, 0x3ec4, 0x2001, 0x000d, 0x0078, 0x3ec4, 0x2001, 0x0009, + 0x0078, 0x3ec4, 0x2001, 0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, + 0x7e5a, 0x70d4, 0xd0b4, 0x0040, 0x3eda, 0xc0b4, 0x70d6, 0x0c7e, + 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, + 0x601a, 0x0c7f, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, + 0x873b, 0x8703, 0x017e, 0xb28c, 0x0300, 0x0040, 0x3eeb, 0xa0e0, + 0x4ec0, 0x0078, 0x3eed, 0xa0e0, 0x4f40, 0x017f, 0xa7b8, 0x0020, + 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040, 0x3efd, 0xa184, 0xfff0, + 0x78a6, 0x6012, 0x6004, 0xc09d, 0x6006, 0x8738, 0x8738, 0x7f9a, + 0x79a4, 0xa184, 0x0040, 0x0040, 0x3f0d, 0xa184, 0xffbf, 0xc0fd, + 0x78a6, 0x6016, 0x6004, 0xc0a5, 0x6006, 0x077f, 0x007c, 0x789b, + 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, + 0x789b, 0x0060, 0x78ab, 0x0004, 0x70d4, 0xd0b4, 0x0040, 0x3f2d, + 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, + 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, 0x2031, 0x0000, + 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, + 0x78ab, 0x0001, 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, + 0x70d4, 0xd0b4, 0x0040, 0x3f51, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, + 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, + 0x0c7f, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, + 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0, 0x2021, 0x3fc6, + 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, 0x2404, 0xa084, + 0xfff0, 0xa106, 0x0040, 0x3f71, 0x8420, 0x2300, 0xa210, 0x00f0, + 0x3f66, 0x157f, 0x007c, 0x157e, 0x2001, 0x4a05, 0x2004, 0xd0e4, + 0x00c0, 0x3fa4, 0x2021, 0x3fd4, 0x20a9, 0x0009, 0x2011, 0x0028, + 0xa582, 0x0019, 0x0040, 0x3fba, 0x0048, 0x3fba, 0x8420, 0x95a9, + 0x2011, 0x0032, 0xa582, 0x0032, 0x0040, 0x3fba, 0x0048, 0x3fba, + 0x8420, 0x95a9, 0x2019, 0x000a, 0x2011, 0x0064, 0x2200, 0xa502, + 0x0040, 0x3fba, 0x0048, 0x3fba, 0x8420, 0x2300, 0xa210, 0x00f0, + 0x3f96, 0x157f, 0x0078, 0x3fb8, 0x2021, 0x3fc6, 0x2019, 0x0011, + 0x20a9, 0x000e, 0x2011, 0x0032, 0x2200, 0xa502, 0x0040, 0x3fba, + 0x0048, 0x3fba, 0x8420, 0x2300, 0xa210, 0x00f0, 0x3fac, 0x157f, + 0xa006, 0x007c, 0x157f, 0xa582, 0x0064, 0x00c8, 0x3fc3, 0x7808, + 0xa085, 0x0070, 0x780a, 0x2404, 0xa005, 0x007c, 0x1209, 0x3002, + 0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, + 0x7a06, 0x0c07, 0x0c07, 0x0e07, 0x10e1, 0x330a, 0x5805, 0x5a05, + 0x6a06, 0x6c06, 0x7c07, 0x7e07, 0x0e00, 0x789b, 0x0010, 0xa046, + 0x007c, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, + 0x8003, 0x8003, 0xa105, 0xd7fc, 0x0040, 0x3ff2, 0xa0e0, 0x6fc0, + 0x0078, 0x3ff4, 0xa0e0, 0x4fc0, 0x007c, 0x0e7e, 0x0f7e, 0xd084, + 0x0040, 0x4002, 0x2079, 0x0100, 0x2009, 0x4a80, 0x2071, 0x4a80, + 0x0078, 0x4014, 0x2009, 0x4a40, 0x007e, 0x2001, 0x4a04, 0x2004, + 0xd0ec, 0x007f, 0x0040, 0x4010, 0x2079, 0x0100, 0x0078, 0x4014, + 0x2079, 0x0200, 0x2071, 0x4a40, 0x2091, 0x8000, 0x2104, 0xa084, + 0x000f, 0x0079, 0x401b, 0x405d, 0x4025, 0x4025, 0x4025, 0x4025, + 0x4025, 0x4023, 0x4023, 0x1078, 0x28ec, 0x784b, 0x0004, 0x7848, + 0xa084, 0x0004, 0x00c0, 0x4027, 0x784b, 0x0008, 0x7848, 0xa084, + 0x0008, 0x00c0, 0x402e, 0x68b4, 0xc0f5, 0x68b6, 0x7858, 0xc0f5, + 0x785a, 0x7830, 0xd0bc, 0x00c0, 0x405d, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x4049, 0xb284, 0x0300, 0x0078, + 0x404b, 0xb284, 0x0400, 0x0040, 0x4051, 0x0018, 0x405d, 0x0078, + 0x4053, 0x0028, 0x405d, 0x681c, 0xd0ac, 0x00c0, 0x405b, 0x1078, + 0x40d5, 0x0078, 0x405d, 0x781b, 0x00f0, 0x2091, 0x8001, 0x0f7f, + 0x0e7f, 0x007c, 0x0c7e, 0x2001, 0x4a01, 0x2004, 0xd0ac, 0x00c0, + 0x40c7, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, + 0xb28c, 0x0300, 0x0040, 0x4078, 0xa0e0, 0x4ec0, 0x0078, 0x407a, + 0xa0e0, 0x4f40, 0x6004, 0xa084, 0x000a, 0x00c0, 0x40c7, 0x6108, + 0xa194, 0xff00, 0x0040, 0x40c7, 0xa18c, 0x00ff, 0x2001, 0x000a, + 0xa106, 0x0040, 0x40a6, 0x2001, 0x000c, 0xa106, 0x0040, 0x40aa, + 0x2001, 0x0012, 0xa106, 0x0040, 0x40ae, 0x2001, 0x0014, 0xa106, + 0x0040, 0x40b2, 0x2001, 0x0019, 0xa106, 0x0040, 0x40b6, 0x2001, + 0x0032, 0xa106, 0x0040, 0x40ba, 0x0078, 0x40be, 0x2009, 0x000c, + 0x0078, 0x40c0, 0x2009, 0x0012, 0x0078, 0x40c0, 0x2009, 0x0014, + 0x0078, 0x40c0, 0x2009, 0x0019, 0x0078, 0x40c0, 0x2009, 0x0020, + 0x0078, 0x40c0, 0x2009, 0x003f, 0x0078, 0x40c0, 0x2011, 0x0000, + 0x2100, 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, + 0x007c, 0x781b, 0x0076, 0x007c, 0x781b, 0x0075, 0x007c, 0x781b, + 0x0064, 0x007c, 0x781b, 0x0061, 0x007c, 0x2009, 0x4a19, 0x210c, + 0xa186, 0x0000, 0x0040, 0x40e7, 0xa186, 0x0001, 0x0040, 0x40ea, + 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c, 0x781b, + 0x00e7, 0x007c, 0x701f, 0x000a, 0x007c, 0x2009, 0x4a19, 0x210c, + 0xa186, 0x0000, 0x0040, 0x4102, 0xa186, 0x0001, 0x0040, 0x40ff, + 0x701f, 0x000b, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c, 0x701f, + 0x000a, 0x007c, 0x781b, 0x00e6, 0x007c, 0x781b, 0x00f0, 0x007c, + 0x781b, 0x00ef, 0x007c, 0x781b, 0x00c0, 0x007c, 0x781b, 0x00bf, + 0x007c, 0x6818, 0xd0fc, 0x0040, 0x4117, 0x681b, 0x001d, 0x7067, + 0x0001, 0x781b, 0x0047, 0x007c, 0x7830, 0xa084, 0x00c0, 0x00c0, + 0x4130, 0x7808, 0xc08c, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, + 0x78ec, 0xa084, 0x0021, 0x0040, 0x4130, 0x7808, 0xc08d, 0x780a, + 0x007c, 0x7808, 0xc08d, 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, + 0x00c0, 0x4135, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x0040, 0x4144, + 0xb284, 0x0300, 0x0078, 0x4146, 0xb284, 0x0400, 0x0040, 0x414c, + 0x0098, 0x4150, 0x0078, 0x414e, 0x00a8, 0x4150, 0x78ac, 0x007c, + 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005, + 0x78ec, 0xa084, 0x0021, 0x0040, 0x4173, 0x007e, 0x2001, 0x4a04, + 0x2004, 0xd0ec, 0x007f, 0x0040, 0x4169, 0xb284, 0x0300, 0x0078, + 0x416b, 0xb284, 0x0400, 0x0040, 0x4171, 0x0098, 0x416d, 0x0078, + 0x4173, 0x00a8, 0x4171, 0x78ac, 0x007e, 0x7808, 0xa085, 0x0002, + 0x780a, 0x007f, 0x007c, 0xa784, 0x0001, 0x00c0, 0x360e, 0xa784, + 0x0070, 0x0040, 0x418b, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x2881, + 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x4198, 0x784b, + 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2946, 0x0078, 0x40c9, + 0xa784, 0x0004, 0x0040, 0x41c7, 0x78b8, 0xa084, 0x4001, 0x0040, + 0x41c7, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2946, + 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x41c7, 0x78c0, + 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00f0, 0x007c, 0x784b, + 0x0008, 0x6818, 0xd0fc, 0x0040, 0x41c4, 0x681b, 0x0015, 0xd6f4, + 0x0040, 0x41c4, 0x681b, 0x0007, 0x1078, 0x40d5, 0x007c, 0x681b, + 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833, + 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2f84, + 0x007e, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x41e4, + 0xb284, 0x0300, 0x0078, 0x41e6, 0xb284, 0x0400, 0x0040, 0x41ec, + 0x0018, 0x2942, 0x0078, 0x41ee, 0x0028, 0x2942, 0x0078, 0x3ea2, + 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, + 0x0040, 0x41fe, 0xa080, 0x4f40, 0x0078, 0x4200, 0xa080, 0x4ec0, + 0x2060, 0x2048, 0x705a, 0x2a60, 0x007c, 0x0020, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, + 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0062, + 0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014, 0x9906, 0x98f4, + 0x0014, 0x0014, 0x0080, 0x00f1, 0x0100, 0x0402, 0x2008, 0xf880, + 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0x2500, 0x0013, + 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, + 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0xa200, + 0x3806, 0x8839, 0x20c4, 0x0864, 0xa850, 0x3008, 0x28c1, 0x9d0d, + 0xa201, 0x300c, 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, + 0x883a, 0xa808, 0x28e2, 0x9cc2, 0xa8f3, 0x0864, 0xa83e, 0x300c, + 0xa801, 0x3008, 0x28e1, 0x9cc2, 0x2021, 0xa81b, 0xa205, 0x870c, + 0xd8de, 0x64a0, 0x6de0, 0x6fc0, 0x63a4, 0x6c80, 0x0212, 0xa205, + 0x883d, 0x9d25, 0x882b, 0x1814, 0x883b, 0x9d2b, 0x883b, 0x7027, + 0x85f2, 0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa812, 0x883e, + 0xa810, 0x280c, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x9d25, + 0x1814, 0x9d2b, 0x883b, 0x7023, 0x8576, 0x8677, 0xa802, 0x7861, + 0x883e, 0x206b, 0x28c1, 0x9d0d, 0x2044, 0x2103, 0x20a2, 0x2081, + 0xa8c9, 0xa207, 0x2901, 0xa80a, 0x0014, 0xa203, 0x8000, 0x85a4, + 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x866f, + 0x7161, 0x0014, 0x0704, 0x3008, 0x9cc2, 0x0014, 0xa202, 0x8000, + 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844, 0x856e, 0x883f, 0x08e6, + 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, + 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, + 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014, 0x3008, 0x8000, 0x284a, + 0x1011, 0xa8fc, 0x3008, 0x9d25, 0x8000, 0xa000, 0x2802, 0x1011, + 0xa8fd, 0x9d2b, 0xa887, 0x3008, 0x9d25, 0x283b, 0x1011, 0xa8fd, + 0xa209, 0x0017, 0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, + 0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, + 0x18f2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d17, + 0x0704, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, + 0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021, + 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822, + 0x0016, 0x7944, 0x8421, 0xa020, 0xa532, 0x84a1, 0x0016, 0x7944, + 0x8421, 0xa0df, 0x9532, 0x84a1, 0x0016, 0x0000, 0x127e, 0x70d4, + 0xa084, 0x4600, 0x8004, 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205, + 0x00c0, 0x4342, 0x720c, 0x82ff, 0x0040, 0x433d, 0x8aff, 0x00c0, + 0x4342, 0x7200, 0xd284, 0x00c0, 0x4342, 0x7003, 0x0008, 0x127f, + 0x2000, 0x007c, 0x7000, 0xa084, 0x0003, 0x7002, 0xc69c, 0xd084, + 0x0040, 0x4374, 0x2001, 0x4a05, 0x2004, 0xd0ec, 0x00c0, 0x43a5, + 0xd0e4, 0x00c0, 0x435a, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0003, + 0x0040, 0x43a5, 0x0e7e, 0x2071, 0x0010, 0x2009, 0x0007, 0x7008, + 0xa084, 0x3000, 0x00c0, 0x435d, 0x8109, 0x00c0, 0x435f, 0x0e7f, + 0x2009, 0x0007, 0x7008, 0xa084, 0x3000, 0x00c0, 0x435a, 0x8109, + 0x00c0, 0x436a, 0x0078, 0x43a5, 0x7108, 0xd1fc, 0x0040, 0x437f, + 0x1078, 0x44ba, 0x8aff, 0x0040, 0x432c, 0x0078, 0x4374, 0x700c, + 0xa08c, 0x03ff, 0x0040, 0x43aa, 0x7004, 0xd084, 0x0040, 0x439c, + 0x7014, 0xa005, 0x00c0, 0x4398, 0x7010, 0x7310, 0xa306, 0x00c0, + 0x438c, 0x2300, 0xa005, 0x0040, 0x439c, 0xa102, 0x00c8, 0x4374, + 0x7007, 0x0010, 0x0078, 0x43a5, 0x8aff, 0x0040, 0x43aa, 0x1078, + 0x46a3, 0x00c0, 0x439f, 0x0040, 0x4374, 0x1078, 0x4443, 0x127f, + 0x2000, 0x007c, 0x7204, 0x7108, 0xc19c, 0x8103, 0x00c8, 0x43b9, + 0x1078, 0x44ba, 0x0078, 0x43aa, 0x7003, 0x0008, 0x127f, 0x2000, + 0x007c, 0xa205, 0x00c0, 0x43a5, 0x7003, 0x0008, 0x127f, 0x2000, + 0x007c, 0x6428, 0x84ff, 0x0040, 0x43ed, 0x2c70, 0x7004, 0xa0bc, + 0x000f, 0xa7b8, 0x43fd, 0x273c, 0x87fb, 0x00c0, 0x43db, 0x0048, + 0x43d3, 0x1078, 0x28ec, 0x609c, 0xa075, 0x0040, 0x43ed, 0x0078, + 0x43c6, 0x2039, 0x43f2, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, + 0xa529, 0x8421, 0x0040, 0x43ed, 0x8738, 0x2704, 0xa005, 0x00c0, + 0x43dc, 0x709c, 0xa075, 0x00c0, 0x43c6, 0x007c, 0x0000, 0x0005, + 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, + 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x43f2, 0x43ef, + 0x0000, 0x0000, 0x8000, 0x0000, 0x43f2, 0x0000, 0x43fa, 0x43f7, + 0x0000, 0x0000, 0x0000, 0x0000, 0x43fa, 0x0000, 0x43f5, 0x43f5, + 0x0000, 0x0000, 0x8000, 0x0000, 0x43f5, 0x0000, 0x43fb, 0x43fb, + 0x0000, 0x0000, 0x0000, 0x0000, 0x43fb, 0x2079, 0x4a00, 0x2071, + 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0001, 0x7810, + 0xd0ec, 0x0040, 0x4431, 0x2009, 0x0001, 0x2071, 0x0020, 0x0078, + 0x4435, 0x2009, 0x0002, 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, + 0x0002, 0x7003, 0x0000, 0x8109, 0x0040, 0x4442, 0x2071, 0x0020, + 0x0078, 0x4435, 0x007c, 0x7004, 0x8004, 0x00c8, 0x44a6, 0x7007, + 0x0012, 0x2019, 0x0000, 0x7108, 0x7008, 0xa106, 0x00c0, 0x444b, + 0xa184, 0x01e0, 0x0040, 0x4456, 0x1078, 0x28ec, 0x7810, 0xd0ec, + 0x0040, 0x4470, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0003, 0x00c0, + 0x4474, 0xa184, 0x4000, 0x0040, 0x4478, 0xa382, 0x0003, 0x00c8, + 0x4478, 0xa184, 0x0004, 0x0040, 0x444b, 0x8318, 0x0078, 0x444b, + 0x7814, 0xd0ec, 0x00c0, 0x4478, 0xa184, 0x4000, 0x00c0, 0x444b, + 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x4486, 0xa386, 0x0008, + 0x0040, 0x4491, 0xa386, 0x200c, 0x00c0, 0x444b, 0x7200, 0x8204, + 0x0048, 0x4491, 0x730c, 0xa384, 0x03ff, 0x0040, 0x4491, 0x1078, + 0x28ec, 0x7007, 0x0012, 0x7000, 0xd084, 0x00c0, 0x44a6, 0x7008, + 0xa084, 0x01e0, 0x00c0, 0x44a6, 0x7310, 0x7014, 0xa305, 0x0040, + 0x44a6, 0x710c, 0xa184, 0x03ff, 0x00c0, 0x4443, 0x7007, 0x0012, + 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, 0x44aa, 0x7007, 0x0012, + 0x7108, 0x8103, 0x0048, 0x44ae, 0x7003, 0x0008, 0x007c, 0x7108, + 0x0078, 0x44ba, 0xa184, 0x01e0, 0x00c0, 0x44ee, 0x7108, 0xa184, + 0x01e0, 0x00c0, 0x44ee, 0xa184, 0x0007, 0x0079, 0x44c7, 0x44d1, + 0x44e1, 0x44cf, 0x44e1, 0x44cf, 0x4533, 0x44cf, 0x4531, 0x1078, + 0x28ec, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x00c0, + 0x44dc, 0x2049, 0x0000, 0x007c, 0x1078, 0x46a3, 0x00c0, 0x44dc, + 0x007c, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x0040, + 0x44ed, 0x1078, 0x46a3, 0x00c0, 0x44e9, 0x007c, 0x7007, 0x0012, + 0x7108, 0x00e0, 0x44f1, 0x2091, 0x6000, 0x00e0, 0x44f5, 0x2091, + 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, + 0x44fd, 0x7007, 0x0012, 0x7108, 0xd1fc, 0x00c0, 0x4501, 0x7003, + 0x0000, 0x7000, 0xa005, 0x00c0, 0x4515, 0x7004, 0xa005, 0x00c0, + 0x4515, 0x700c, 0xa005, 0x0040, 0x4517, 0x0078, 0x44f9, 0x2049, + 0x0000, 0xb284, 0x0100, 0x0040, 0x4521, 0x2001, 0x0000, 0x0078, + 0x4523, 0x2001, 0x0001, 0x1078, 0x3ff5, 0x6818, 0xa084, 0x8000, + 0x0040, 0x452c, 0x681b, 0x0002, 0x007c, 0x1078, 0x28ec, 0x1078, + 0x28ec, 0x1078, 0x4570, 0x7210, 0x7114, 0x700c, 0xa09c, 0x03ff, + 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x4570, 0x2704, + 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, + 0x2400, 0xa305, 0x0040, 0x4556, 0x00c8, 0x4556, 0x8412, 0x8210, + 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x453d, 0x2b60, 0x8a07, + 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x4562, 0xa7ba, 0x43f7, + 0x0078, 0x4564, 0xa7ba, 0x43ef, 0x007f, 0xa73d, 0x2c00, 0x6886, + 0x6f8a, 0x6c92, 0x6b8e, 0x7007, 0x0012, 0x1078, 0x4443, 0x007c, + 0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x4584, 0x6000, 0xa064, + 0x00c0, 0x457b, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, 0x440d, + 0x203c, 0x87fb, 0x1040, 0x28ec, 0x007c, 0x127e, 0x0d7e, 0x70d4, + 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x6884, 0x2060, 0x6888, + 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, + 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x45a2, 0xa0b8, 0x43f7, + 0x0078, 0x45a4, 0xa0b8, 0x43ef, 0xb284, 0x0100, 0x0040, 0x45ab, + 0x7e20, 0x0078, 0x45ac, 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0b4, + 0x0040, 0x45b3, 0xc685, 0x2400, 0xa305, 0x0040, 0x45dd, 0x2c58, + 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, + 0x701e, 0xa184, 0x0008, 0x0040, 0x45cd, 0x6010, 0xa081, 0x0000, + 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, + 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, + 0x2b60, 0x1078, 0x46c6, 0x0078, 0x45df, 0x1078, 0x46a3, 0x00c0, + 0x45dd, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, + 0x4600, 0x8004, 0x2090, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xd094, + 0x00c0, 0x45ee, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, + 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x7e20, + 0xb284, 0x0100, 0x00c0, 0x4605, 0x7e24, 0xa6b5, 0x000c, 0x681c, + 0xd0ac, 0x00c0, 0x4610, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004, + 0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x43fd, + 0x273c, 0x87fb, 0x00c0, 0x4626, 0x0048, 0x4620, 0x1078, 0x28ec, + 0x689c, 0xa065, 0x0040, 0x462a, 0x0078, 0x4613, 0x1078, 0x46a3, + 0x00c0, 0x4626, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e, + 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x7e20, 0xb284, + 0x0100, 0x00c0, 0x463c, 0x7e24, 0x0d7f, 0x037f, 0x047f, 0xa6b5, + 0x000c, 0x681c, 0xd0b4, 0x0040, 0x464a, 0xc685, 0x7003, 0x0000, + 0x7007, 0x0004, 0x2049, 0x462d, 0x6828, 0xa055, 0x0040, 0x46a0, + 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x43fd, 0x273c, + 0x87fb, 0x00c0, 0x4666, 0x0048, 0x465f, 0x1078, 0x28ec, 0x709c, + 0xa075, 0x2060, 0x0040, 0x46a0, 0x0078, 0x4652, 0x2704, 0xae68, + 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, 0x467f, 0x8a51, 0x00c0, + 0x4673, 0x1078, 0x28ec, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4667, + 0x709c, 0xa075, 0x2060, 0x0040, 0x46a0, 0x0078, 0x4652, 0x8422, + 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, + 0x2300, 0xa11b, 0x00c8, 0x468e, 0x1078, 0x28ec, 0xb284, 0x0100, + 0x0040, 0x469c, 0x2001, 0x4a04, 0x2004, 0xd0ec, 0x00c0, 0x469c, + 0x2071, 0x0050, 0x0078, 0x469e, 0x2071, 0x0020, 0x0078, 0x45b3, + 0x127f, 0x2000, 0x007c, 0x7008, 0xa084, 0x0003, 0xa086, 0x0003, + 0x00c0, 0x46ab, 0x007c, 0x2704, 0xac78, 0x7800, 0x701a, 0x7804, + 0x701e, 0x7808, 0x7012, 0x780c, 0x7016, 0x6004, 0xa084, 0x0008, + 0x0040, 0x46be, 0x7810, 0x7022, 0x7814, 0x7026, 0x7602, 0x7004, + 0xa084, 0x0010, 0xc085, 0x7006, 0x2079, 0x4a00, 0x8a51, 0x0040, + 0x46e1, 0x8738, 0x2704, 0xa005, 0x00c0, 0x46dc, 0x609c, 0xa005, + 0x0040, 0x46e2, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x43fd, + 0x203c, 0x87fb, 0x1040, 0x28ec, 0x7008, 0xa084, 0x0003, 0xa086, + 0x0003, 0x007c, 0x2051, 0x0000, 0x007c, 0x127e, 0x007e, 0x0d7e, + 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x087f, 0x7108, + 0xa184, 0x0003, 0x00c0, 0x46fa, 0x6828, 0xa005, 0x0040, 0x470a, + 0x0078, 0x4342, 0x7108, 0xd1fc, 0x0040, 0x4702, 0x1078, 0x44ba, + 0x0078, 0x46ef, 0x7007, 0x0010, 0x7108, 0xd1fc, 0x0040, 0x4704, + 0x1078, 0x44ba, 0x7008, 0xa086, 0x0008, 0x00c0, 0x46ef, 0x7000, + 0xa005, 0x00c0, 0x46ef, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, + 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, + 0x70d4, 0xa084, 0x4600, 0x8004, 0x2090, 0x0d7f, 0x2049, 0x471a, + 0xad80, 0x0011, 0x20a0, 0xb284, 0x0100, 0x0040, 0x473d, 0x2001, + 0x4a04, 0x2004, 0xd0ec, 0x0040, 0x4739, 0x2099, 0x0031, 0x0078, + 0x473f, 0x2099, 0x0032, 0x0078, 0x473f, 0x2099, 0x0031, 0x700c, + 0xa084, 0x03ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, + 0x0001, 0x0040, 0x474e, 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, + 0x03ff, 0x0040, 0x475a, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, + 0x00c0, 0x4755, 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, + 0x137f, 0x147f, 0x127f, 0x2000, 0x007c, 0x2091, 0x8000, 0x2091, + 0x6000, 0x78ac, 0xa005, 0x00c0, 0x477c, 0x7974, 0x70d0, 0xa106, + 0x00c0, 0x477c, 0x781c, 0xa005, 0x0040, 0x477c, 0x781f, 0x0000, + 0x0068, 0x477c, 0x2091, 0x4080, 0x7830, 0x8001, 0x7832, 0x00c0, + 0x4804, 0x7834, 0x7832, 0x7810, 0xd0ec, 0x00c0, 0x47fd, 0x2061, + 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x68d0, 0xa005, 0x0040, 0x4796, + 0x8001, 0x68d2, 0x00c0, 0x4796, 0x1078, 0x4998, 0x6800, 0xa084, + 0x000f, 0x0040, 0x47ab, 0xa086, 0x0001, 0x0040, 0x47ab, 0x6844, + 0xa00d, 0x0040, 0x47ab, 0x2104, 0xa005, 0x0040, 0x47ab, 0x8001, + 0x200a, 0x0040, 0x4909, 0x6814, 0xa005, 0x0040, 0x47d0, 0x8001, + 0x6816, 0x00c0, 0x47d0, 0x68a7, 0x0001, 0x0f7e, 0xd7fc, 0x00c0, + 0x47c5, 0x7810, 0xd0ec, 0x0040, 0x47c1, 0x2079, 0x0100, 0x0078, + 0x47c7, 0x2079, 0x0200, 0x0078, 0x47c7, 0x2079, 0x0100, 0x1078, + 0x4131, 0x0f7f, 0x6864, 0xa005, 0x0040, 0x47d0, 0x1078, 0x25de, + 0x6880, 0xa005, 0x0040, 0x47dd, 0x8001, 0x6882, 0x00c0, 0x47dd, + 0x6867, 0x0000, 0x68d4, 0xc0dd, 0x68d6, 0x68d4, 0xd0fc, 0x0040, + 0x47fa, 0xc0fc, 0x68d6, 0x20a9, 0x0200, 0x603c, 0xa005, 0x0040, + 0x47f6, 0x8001, 0x603e, 0x68d4, 0xc0fd, 0x68d6, 0x00c0, 0x47f6, + 0x6010, 0xa005, 0x0040, 0x47f6, 0x1078, 0x25de, 0xace0, 0x0010, + 0x00f0, 0x47e5, 0xd7fc, 0x0040, 0x4804, 0x2061, 0x4fc0, 0x2069, + 0x4a40, 0xc7fc, 0x0078, 0x478c, 0x1078, 0x4840, 0x7838, 0x8001, + 0x783a, 0x00c0, 0x4826, 0x783c, 0x783a, 0x2061, 0x4fc0, 0x2069, + 0x4a40, 0xc7fc, 0x680c, 0xa005, 0x0040, 0x4818, 0x1078, 0x487f, + 0xd7fc, 0x00c0, 0x4826, 0x7810, 0xd0ec, 0x00c0, 0x4826, 0x2061, + 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x0078, 0x4812, 0x7814, 0xd0e4, + 0x00c0, 0x482a, 0x7810, 0xd0cc, 0x0040, 0x483d, 0xd0ac, 0x00c0, + 0x4836, 0xd0a4, 0x0040, 0x483d, 0xc0ad, 0x7812, 0x2091, 0x8001, + 0x0068, 0x483c, 0x1078, 0x2368, 0x007c, 0x2091, 0x8001, 0x007c, + 0x7840, 0x8001, 0x7842, 0x00c0, 0x487e, 0x7844, 0x7842, 0x2091, + 0x8000, 0x2061, 0x4fc0, 0x2069, 0x4a40, 0xc7fc, 0x6810, 0xa005, + 0x00c0, 0x4854, 0x2001, 0x0101, 0x8001, 0x6812, 0xd7fc, 0x0040, + 0x485d, 0xa080, 0x90d0, 0x0078, 0x485f, 0xa080, 0x8fc0, 0x2040, + 0x2004, 0xa065, 0x0040, 0x4870, 0x6024, 0xa005, 0x0040, 0x486c, + 0x8001, 0x6026, 0x0040, 0x48ad, 0x6000, 0x2c40, 0x0078, 0x4861, + 0xd7fc, 0x00c0, 0x487e, 0x7810, 0xd0ec, 0x00c0, 0x487e, 0x2061, + 0x6fc0, 0x2069, 0x4a80, 0xc7fd, 0x0078, 0x484e, 0x007c, 0x2009, + 0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0040, 0x4899, 0x6024, + 0xa005, 0x0040, 0x488f, 0x8001, 0x6026, 0x0078, 0x4897, 0x6008, + 0xc09c, 0xc0bd, 0x600a, 0xa18d, 0x0001, 0x0078, 0x4899, 0xa18d, + 0x0100, 0xace0, 0x0010, 0x00f0, 0x4883, 0xa184, 0x0001, 0x0040, + 0x48a8, 0xa18c, 0xfffe, 0x690e, 0x1078, 0x25de, 0x0078, 0x48a9, + 0x690e, 0x007c, 0x00c0, 0x48a9, 0x786c, 0x6800, 0xa005, 0x0040, + 0x48b5, 0x684c, 0xac06, 0x0040, 0x4909, 0x6864, 0xa005, 0x0040, + 0x48bd, 0x6027, 0x0001, 0x0078, 0x4906, 0x2c00, 0x687e, 0x601b, + 0x0006, 0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, + 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, 0x6714, 0x6f76, 0x1078, + 0x1e02, 0x6818, 0xa005, 0x0040, 0x48d7, 0x8001, 0x681a, 0x6808, + 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x00d0, + 0x48e3, 0x1078, 0x28ec, 0x6812, 0x00c0, 0x48e9, 0x7910, 0xc1a5, + 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x202a, + 0xd7fc, 0x00c0, 0x48f7, 0x2069, 0x4a40, 0x0078, 0x48f9, 0x2069, + 0x4a80, 0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x00c0, 0x4903, + 0x697a, 0x2001, 0x0004, 0x2708, 0x1078, 0x25d1, 0x2091, 0x8001, + 0x007c, 0x0d7e, 0x694c, 0x2160, 0xd7fc, 0x00c0, 0x491b, 0x7810, + 0xd0ec, 0x0040, 0x4917, 0x2069, 0x0100, 0x0078, 0x491d, 0x2069, + 0x0200, 0x0078, 0x491d, 0x2069, 0x0100, 0x1078, 0x2881, 0x601b, + 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, + 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, 0x6830, + 0xd0b4, 0x0040, 0x494b, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, + 0xd094, 0x0040, 0x493d, 0x00f0, 0x4937, 0x684b, 0x0009, 0x20a9, + 0x0014, 0x6848, 0xd084, 0x0040, 0x4947, 0x00f0, 0x4941, 0x20a9, + 0x00fa, 0x00f0, 0x4949, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, + 0x0047, 0x0d7f, 0x6867, 0x0007, 0x2091, 0x8001, 0x007c, 0x2079, + 0x4a00, 0x1078, 0x498b, 0x1078, 0x4971, 0x1078, 0x497e, 0x2009, + 0x0002, 0x2069, 0x4a80, 0x680f, 0x0000, 0x6813, 0x0000, 0x6817, + 0x0000, 0x8109, 0x0040, 0x4970, 0x2069, 0x4a40, 0x0078, 0x4963, + 0x007c, 0x7810, 0xd0ec, 0x0040, 0x4979, 0x2019, 0x00cc, 0x0078, + 0x497b, 0x2019, 0x007b, 0x7b3a, 0x7b3e, 0x007c, 0x7814, 0xd0e4, + 0x00c0, 0x4986, 0x2019, 0x0040, 0x0078, 0x4988, 0x2019, 0x0026, + 0x7b42, 0x7b46, 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x4993, 0x2019, + 0x3f94, 0x0078, 0x4995, 0x2019, 0x2624, 0x7b32, 0x7b36, 0x007c, + 0x6950, 0xa185, 0x0000, 0x0040, 0x49ad, 0x0c7e, 0x6ac0, 0x2264, + 0x602b, 0x0000, 0x602f, 0x0000, 0x6008, 0xc0b5, 0x600a, 0x8210, + 0x8109, 0x00c0, 0x499f, 0x6952, 0x0c7f, 0x007c, 0x70ec, 0xd0dc, + 0x00c0, 0x49b7, 0xd0d4, 0x0040, 0x49d6, 0x0078, 0x49d9, 0x7810, + 0xd0ec, 0x0040, 0x49c2, 0xc0f5, 0x7812, 0xd0ec, 0x0040, 0x49dd, + 0x0078, 0x49d9, 0xae8e, 0x0100, 0x0040, 0x49ce, 0x7814, 0xc0f5, + 0x7816, 0xd0d4, 0x00c0, 0x49dd, 0x0078, 0x49d9, 0x7814, 0xc0fd, + 0x7816, 0xd0d4, 0x00c0, 0x49dd, 0x0078, 0x49d9, 0xd0e4, 0x0040, + 0x49df, 0x7804, 0xd08c, 0x0040, 0x49df, 0x681f, 0x000c, 0x70a0, + 0x70a2, 0x007c, 0x699a +}; +unsigned short fw1280ei_length01 = 0x39e3; + diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c --- v2.3.42/linux/drivers/scsi/qla1280.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/qla1280.c Tue Feb 8 12:01:59 2000 @@ -0,0 +1,6850 @@ +/******************************************************************************** + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP1x80/1x160 device driver for Linux 2.3.x (redhat 6.X). + * + * COPYRIGHT (C) 1999-2000 QLOGIC CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Qlogic's Linux Software License. See below. + * + * This program is WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistribution's or source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + ********************************************************************************/ + +/***************************************************************************************** + QLOGIC CORPORATION SOFTWARE + "GNU" GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION + AND MODIFICATION + +This GNU General Public License ("License") applies solely to QLogic Linux +Software ("Software") and may be distributed under the terms of this License. + +1. You may copy and distribute verbatim copies of the Software's source code as +you receive it, in any medium, provided that you conspicuously and appropriately +publish on each copy an appropriate copyright notice and disclaimer of warranty; +keep intact all the notices that refer to this License and to the absence of any +warranty; and give any other recipients of the Software a copy of this License along +with the Software. + +You may charge a fee for the physical act of transferring a copy, and you may at your +option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Software or any portion of it, thus forming +a work based on the Software, and copy and distribute such modifications or work under +the terms of Section 1 above, provided that you also meet all of these conditions: + +* a) You must cause the modified files to carry prominent notices stating that you +changed the files and the date of any change. + +* b) You must cause any work that you distribute or publish that in whole or in part +contains or is derived from the Software or any part thereof, to be licensed as a +whole at no charge to all third parties under the terms of this License. + +* c) If the modified Software normally reads commands interactively when run, you +must cause it, when started running for such interactive use in the most ordinary way, +to print or display an announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide a warranty) and that +users may redistribute the Software under these conditions, and telling the user how to +view a copy of this License. (Exception:if the Software itself is interactive but does +not normally print such an announcement, your work based on the Software is not required +to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable sections of +that work are not derived from the Software, and can be reasonably considered independent +and separate works in themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you distribute the same +sections as part of a whole which is a work based on the Software, the distribution of the +whole must be on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote it. + +3. You may copy and distribute the Software (or a work based on it, under Section 2) in +object code or executable form under the terms of Sections 1 and 2 above provided that +you also do one of the following: + +* a) Accompany it with the complete corresponding machine-readable source code, which must +be distributed under the terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or, + +* b) Accompany it with a written offer, valid for at least three years, to give any third +party, for a charge no more than your cost of physically performing source distribution, +a complete machine-readable copy of the corresponding source code, to be distributed under +the terms of Sections 1 and 2 above on a medium customarily used for software interchange; +or, + +* c) Accompany it with the information you received as to the offer to distribute +corresponding source code. (This alternative is allowed only for noncommercial distribution +and only if you received the Software in object code or executable form with such an offer, +in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications +to it. For an executable work, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus the scripts used +to control compilation and installation of the executable. + +If distribution of executable or object code is made by offering access to copy from a +designated place, then offering equivalent access to copy the source code from the same +place counts as distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Software except as expressly +provided under this License. Any attempt otherwise to copy, modify, sublicense or +distribute the Software is void, and will automatically terminate your rights under this +License. However, parties who have received copies, or rights, from you under this License +will not have their licenses terminated so long as such parties remain in full compliance. + +5. This license grants you world wide, royalty free non-exclusive rights to modify or +distribute the Software or its derivative works. These actions are prohibited by law +if you do not accept this License. Therefore, by modifying or distributing the Software +(or any work based on the Software), you indicate your acceptance of this License to do +so, and all its terms and conditions for copying, distributing or modifying the Software +or works based on it. + +6. Each time you redistribute the Software (or any work based on the Software), the +recipient automatically receives a license from the original licensor to copy, distribute +or modify the Software subject to these terms and conditions. You may not impose any +further restrictions on the recipients' exercise of the rights granted herein. You are +not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for +any other reason (not limited to patent issues), conditions are imposed on you +(whether by court order, agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this License +and any other pertinent obligations, then as a consequence you may not distribute the +Software at all. + +If any portion of this section is held invalid or unenforceable under any particular +circumstance, the balance of the section is intended to apply and the section as a whole +is intended to apply in other circumstances. +NO WARRANTY + +11. THE SOFTWARE IS PROVIDED WITHOUT A WARRANTY OF ANY KIND. THERE IS NO +WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. +SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE SOFTWARE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING +BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO +OPERATE WITH ANY OTHER SOFTWARES), EVEN IF SUCH HOLDER OR OTHER PARTY HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +*******************************************************************************************/ + +/**************************************************************************** + Revision History: + Rev. 3.00 Jan 17, 1999 DG Qlogic + - Added 64-bit support. + Rev. 2.07 Nov 9, 1999 DG Qlogic + - Added new routine to set target parameters for ISP12160. + Rev. 2.06 Sept 10, 1999 DG Qlogic + - Added support for ISP12160 Ultra 3 chip. + Rev. 2.03 August 3, 1999 Fred Lewis, Intel DuPont + - Modified code to remove errors generated when compiling with + Cygnus IA64 Compiler. + - Changed conversion of pointers to unsigned longs instead of integers. + - Changed type of I/O port variables from uint32_t to unsigned long. + - Modified OFFSET macro to work with 64-bit as well as 32-bit. + - Changed sprintf and printk format specifiers for pointers to %p. + - Changed some int to long type casts where needed in sprintf & printk. + - Added l modifiers to sprintf and printk format specifiers for longs. + - Removed unused local variables. + Rev. 1.20 June 8, 1999 DG, Qlogic + Changes to support RedHat release 6.0 (kernel 2.2.5). + - Added SCSI exclusive access lock (io_request_lock) when accessing + the adapter. + - Added changes for the new LINUX interface template. Some new error + handling routines have been added to the template, but for now we + will use the old ones. + - Initial Beta Release. +*****************************************************************************/ + +#ifdef MODULE +#include +#endif + +#define QLA1280_VERSION " 3.00-Beta" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* MRS #include */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +# include +#endif +#include "sd.h" +#include "scsi.h" +#include "hosts.h" +#define UNIQUE_FW_NAME +#include "qla1280.h" +#include "ql12160_fw.h" /* ISP RISC code */ +#include "ql1280_fw.h" + +#include +#include /* for kmalloc() */ + + +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + + +/* + * Compile time Options: + * 0 - Disable and 1 - Enable + */ +#define QLA1280_64BIT_SUPPORT 1 /* 64-bit Support */ +#define QL1280_TARGET_MODE_SUPPORT 0 /* Target mode support */ +#define WATCHDOGTIMER 0 +#define MEMORY_MAPPED_IO 0 +#define DEBUG_QLA1280_INTR 0 +#define USE_NVRAM_DEFAULTS 0 +#define DEBUG_PRINT_NVRAM 0 +#define LOADING_RISC_ACTIVITY 0 +#define AUTO_ESCALATE_RESET 0 /* Automatically escalate resets */ +#define AUTO_ESCALATE_ABORT 0 /* Automatically escalate aborts */ +#define STOP_ON_ERROR 0 /* Stop on aborts and resets */ +#define STOP_ON_RESET 0 +#define STOP_ON_ABORT 0 +#undef DYNAMIC_MEM_ALLOC + +#define DEBUG_QLA1280 0 /* Debugging */ +/* #define CHECKSRBSIZE */ + +/* + * These macros to assist programming + */ + +#define BZERO(ptr, amt) memset(ptr, 0, amt) +#define BCOPY(src, dst, amt) memcpy(dst, src, amt) +#define KMALLOC(siz) kmalloc((siz), GFP_ATOMIC) +#define KMFREE(ip,siz) kfree((ip)) +#define SYS_DELAY(x) udelay(x);barrier() +#define QLA1280_DELAY(sec) mdelay(sec * 1000) +#define VIRT_TO_BUS(a) virt_to_bus((a)) +#if QLA1280_64BIT_SUPPORT +#if BITS_PER_LONG <= 32 +#define VIRT_TO_BUS_LOW(a) (uint32_t)virt_to_bus((a)) +#define VIRT_TO_BUS_HIGH(a) (uint32_t)(0x0) +#else +#define VIRT_TO_BUS_LOW(a) (uint32_t)(0xffffffff & virt_to_bus((a))) +#define VIRT_TO_BUS_HIGH(a) (uint32_t)(0xffffffff & (virt_to_bus((a))>>32)) +#endif +#endif /* QLA1280_64BIT_SUPPORT */ + +#define STATIC + +#define NVRAM_DELAY() udelay(500) /* 2 microsecond delay */ +void qla1280_device_queue_depth(scsi_qla_host_t *, Scsi_Device *); + +#define CACHE_FLUSH(a) (RD_REG_WORD(a)) +#define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS+1) + +#define MSW(x) (uint16_t)((uint32_t)(x) >> 16) +#define LSW(x) (uint16_t)(x) +#define MSB(x) (uint8_t)((uint16_t)(x) >> 8) +#define LSB(x) (uint8_t)(x) + +#if BITS_PER_LONG <= 32 +#define LS_64BITS(x) (uint32_t)(x) +#define MS_64BITS(x) (uint32_t)(0x0) +#else +#define LS_64BITS(x) (uint32_t)(0xffffffff & (x)) +#define MS_64BITS(x) (uint32_t)(0xffffffff & ((x)>>32) ) +#endif + +/* + * QLogic Driver Support Function Prototypes. + */ +STATIC void qla1280_done(scsi_qla_host_t *, srb_t **, srb_t **); +STATIC void qla1280_next(scsi_qla_host_t *, scsi_lu_t *, uint8_t); +STATIC void qla1280_putq_t(scsi_lu_t *, srb_t *); +STATIC void qla1280_done_q_put(srb_t *, srb_t **, srb_t **); +STATIC void qla1280_select_queue_depth(struct Scsi_Host *, Scsi_Device *); +#ifdef QLA1280_UNUSED +static void qla1280_dump_regs(struct Scsi_Host *host); +#endif +#if STOP_ON_ERROR +static void qla1280_panic(char *, struct Scsi_Host *host); +#endif +void qla1280_print_scsi_cmd(Scsi_Cmnd *cmd); +STATIC void qla1280_abort_queue_single(scsi_qla_host_t *,uint32_t,uint32_t,uint32_t,uint32_t); + +STATIC int qla1280_return_status( sts_entry_t *sts, Scsi_Cmnd *cp); +STATIC void qla1280_removeq(scsi_lu_t *q, srb_t *sp); +STATIC void qla1280_mem_free(scsi_qla_host_t *ha); +void qla1280_do_dpc(void *p); +#ifdef QLA1280_UNUSED +static void qla1280_set_flags(char * s); +#endif +static char *qla1280_get_token(char *, char *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +STATIC inline void mdelay(int); +#endif +static inline void qla1280_enable_intrs(scsi_qla_host_t *); +static inline void qla1280_disable_intrs(scsi_qla_host_t *); + +/* + * QLogic ISP1280 Hardware Support Function Prototypes. + */ +STATIC uint8_t qla1280_initialize_adapter(struct scsi_qla_host *ha); +STATIC uint8_t qla1280_enable_tgt(scsi_qla_host_t *, uint8_t); +STATIC uint8_t qla1280_isp_firmware(scsi_qla_host_t *); +STATIC uint8_t qla1280_pci_config(scsi_qla_host_t *); +STATIC uint8_t qla1280_chip_diag(scsi_qla_host_t *); +STATIC uint8_t qla1280_setup_chip(scsi_qla_host_t *); +STATIC uint8_t qla1280_init_rings(scsi_qla_host_t *); +STATIC uint8_t qla1280_nvram_config(scsi_qla_host_t *); +STATIC uint8_t qla1280_mailbox_command(scsi_qla_host_t *, uint8_t, uint16_t *); +STATIC uint8_t qla1280_bus_reset(scsi_qla_host_t *, uint8_t); +STATIC uint8_t qla1280_device_reset(scsi_qla_host_t *, uint8_t, uint32_t); +STATIC uint8_t qla1280_abort_device(scsi_qla_host_t *, uint8_t, uint32_t, uint32_t); +STATIC uint8_t qla1280_abort_command(scsi_qla_host_t *, srb_t *), +#if QLA1280_64BIT_SUPPORT + qla1280_64bit_start_scsi(scsi_qla_host_t *, srb_t *), +#endif + qla1280_32bit_start_scsi(scsi_qla_host_t *, srb_t *), + qla1280_abort_isp(scsi_qla_host_t *); +STATIC void qla1280_nv_write(scsi_qla_host_t *, uint16_t), + qla1280_nv_delay(scsi_qla_host_t *), + qla1280_poll(scsi_qla_host_t *), + qla1280_reset_adapter(scsi_qla_host_t *), + qla1280_marker(scsi_qla_host_t *, uint8_t, uint32_t, uint32_t, uint8_t), + qla1280_isp_cmd(scsi_qla_host_t *), + qla1280_isr(scsi_qla_host_t *, srb_t **, srb_t **), + qla1280_rst_aen(scsi_qla_host_t *), + qla1280_status_entry(scsi_qla_host_t *, sts_entry_t *, srb_t **, + srb_t **), + qla1280_error_entry(scsi_qla_host_t *, response_t *, srb_t **, + srb_t **), + qla1280_restart_queues(scsi_qla_host_t *), + qla1280_abort_queues(scsi_qla_host_t *); +STATIC uint16_t qla1280_get_nvram_word(scsi_qla_host_t *, uint32_t), + qla1280_nvram_request(scsi_qla_host_t *, uint32_t), + qla1280_debounce_register(volatile uint16_t *); +STATIC request_t *qla1280_req_pkt(scsi_qla_host_t *); +int qla1280_check_for_dead_scsi_bus(scsi_qla_host_t *ha, srb_t *sp); +STATIC uint8_t qla1280_mem_alloc(scsi_qla_host_t *ha); +STATIC uint8_t qla1280_register_with_Linux(scsi_qla_host_t *ha, uint8_t maxchannels); + +STATIC uint8_t qla12160_set_target_parameters(scsi_qla_host_t *, uint32_t, uint32_t, uint32_t, nvram160_t *); +STATIC void qla12160_get_target_parameters(scsi_qla_host_t *, uint32_t, uint32_t, uint32_t); + +#if QL1280_TARGET_MODE_SUPPORT +STATIC void qla1280_enable_lun(scsi_qla_host_t *, uint8_t, uint32_t), + qla1280_notify_ack(scsi_qla_host_t *, notify_entry_t *), + qla1280_immed_notify(scsi_qla_host_t *, notify_entry_t *), + qla1280_accept_io(scsi_qla_host_t *, ctio_ret_entry_t *), +#if QLA1280_64BIT_SUPPORT + qla1280_64bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t, + paddr32_t *), +#endif + qla1280_32bit_continue_io(scsi_qla_host_t *, atio_entry_t *, uint32_t, + paddr32_t *), + qla1280_atio_entry(scsi_qla_host_t *, atio_entry_t *), + qla1280_notify_entry(scsi_qla_host_t *, notify_entry_t *); +#endif /* QLA1280_TARGET_MODE_SUPPORT */ + +#ifdef QL_DEBUG_ROUTINES +/* + * Driver Debug Function Prototypes. + */ +STATIC uint8_t qla1280_getbyte(uint8_t *); +STATIC uint16_t qla1280_getword(uint16_t *); +STATIC uint32_t qla1280_getdword(uint32_t *); +STATIC void qla1280_putbyte(uint8_t *, uint8_t), + qla1280_putword(uint16_t *, uint16_t), + qla1280_putdword(uint32_t *, uint32_t), + qla1280_print(caddr_t), + qla1280_output_number(uint32_t, uint8_t), + qla1280_putc(uint8_t), + qla1280_dump_buffer(caddr_t, uint32_t); + +char debug_buff[80]; +#if DEBUG_QLA1280 +STATIC uint8_t ql_debug_print = 1; +#else +STATIC uint8_t ql_debug_print = 0; +#endif +#endif + +/* + * insmod needs to find the variable and make it point to something + */ +#ifdef MODULE +static char *options = NULL; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,18) + +/* insmod qla1280 options=verbose" */ +MODULE_PARM(options, "s"); +#endif +/* + * Just in case someone uses commas to separate items on the insmod + * command line, we define a dummy buffer here to avoid having insmod + * write wild stuff into our code segment + */ +static char dummy_buffer[60] = "Please don't add commas in your insmod command!!\n"; + +#endif + + +/* + * Our directory Entry in /proc/scsi for the user to + * access the driver. + */ + +#if 0 + +/* Need to add in proc_fs.h PROC_SCSI_QL1280 */ +#define PROC_SCSI_QL1280 PROC_SCSI_QLOGICISP + +struct proc_dir_entry proc_scsi_qla1280 = { + PROC_SCSI_QL1280, 7, "qla1280", + S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +#endif + +/* We use the Scsi_Pointer structure that's included with each command + * SCSI_Cmnd as a scratchpad for our SRB. + * + * SCp will always point to the SRB structure (defined in qla1280.h). + * It is define as follows: + * - SCp.ptr -- > pointer back to the cmd + * - SCp.this_residual --> used as forward pointer to next srb + * - SCp.buffer --> used as backward pointer to next srb + * - SCp.buffers_residual --> used as flags field + * - SCp.have_data_in --> not used + * - SCp.sent_command --> not used + * - SCp.phase --> not used + */ + +#define CMD_SP(Cmnd) (&(Cmnd)->SCp) +#define CMD_XFRLEN(Cmnd) (Cmnd)->request_bufflen +#define CMD_CDBLEN(Cmnd) (Cmnd)->cmd_len +#define CMD_CDBP(Cmnd) (Cmnd)->cmnd +#define CMD_SNSP(Cmnd) (Cmnd)->sense_buffer +#define CMD_SNSLEN(Cmnd) (sizeof (Cmnd)->sense_buffer) +#define CMD_RESULT(Cmnd) ((Cmnd)->result) +#define CMD_HANDLE(Cmnd) ((Cmnd)->host_scribble) + +/*****************************************/ +/* ISP Boards supported by this driver */ +/*****************************************/ +#define QLA1280_VENDOR_ID 0x1077 +#define QLA1080_DEVICE_ID 0x1080 +#define QLA1240_DEVICE_ID 0x1240 +#define QLA1280_DEVICE_ID 0x1280 +#define QLA12160_DEVICE_ID 0x1216 +#define QLA10160_DEVICE_ID 0x1016 +#define NUM_OF_ISP_DEVICES 6 + +typedef struct _qlaboards +{ + unsigned char bdName[9]; /* Board ID String */ + unsigned long device_id; /* Device PCI ID */ + int numPorts; /* Number of SCSI ports */ + unsigned short *fwcode; /* pointer to FW array */ + unsigned long *fwlen; /* number of words in array */ + unsigned short *fwstart; /* start address for F/W */ + unsigned char *fwver; /* Ptr to F/W version array */ +} qla_boards_t; + +struct _qlaboards QLBoardTbl[NUM_OF_ISP_DEVICES] = +{ + /* Name , Board PCI Device ID, Number of ports */ + {"QLA1080 ", QLA1080_DEVICE_ID, 1, + &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, + {"QLA1240 ", QLA1240_DEVICE_ID, 2, + &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, + {"QLA1280 ", QLA1280_DEVICE_ID, 2, + &fw1280ei_code01[0], (unsigned long *)&fw1280ei_length01,&fw1280ei_addr01, &fw1280ei_version_str[0] }, + {"QLA12160 ", QLA12160_DEVICE_ID, 2, + &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] }, + {"QLA10160 ", QLA10160_DEVICE_ID, 1, + &fw12160i_code01[0], (unsigned long *)&fw12160i_length01,&fw12160i_addr01, &fw12160i_version_str[0] }, + {" ", 0, 0} +}; + +static unsigned long qla1280_verbose = 1L; +static scsi_qla_host_t *qla1280_hostlist = NULL; +#ifdef QLA1280_PROFILE +static int qla1280_buffer_size = 0; +static char *qla1280_buffer = NULL; +#endif + +#ifdef QL_DEBUG_LEVEL_3 +#define ENTER(x) sprintf(debug_buff,"qla1280 : Entering %s()\n\r", x); \ + qla1280_print(debug_buff); +#define LEAVE(x) sprintf(debug_buff,"qla1280 : Leaving %s()\n\r", x); \ + qla1280_print(debug_buff); +#define ENTER_INTR(x) sprintf(debug_buff,"qla1280 : Entering %s()\n\r", x); \ + qla1280_print(debug_buff); +#define LEAVE_INTR(x) sprintf(debug_buff,"qla1280 : Leaving %s()\n\r", x); \ + qla1280_print(debug_buff); +#define DEBUG3(x) x +#else +#define ENTER(x) +#define LEAVE(x) +#define ENTER_INTR(x) +#define LEAVE_INTR(x) +#define DEBUG3(x) +#endif + +#if DEBUG_QLA1280 +#define COMTRACE(x) +/* #define COMTRACE(x) qla1280_putc(x); */ +#define DEBUG(x) x +#else +#define DEBUG(x) +#define COMTRACE(x) +#endif + +#ifdef QL_DEBUG_LEVEL_2 +#define DEBUG2(x) x +#else +#define DEBUG2(x) +#endif +#define DEBUG5(x) + +#if (BITS_PER_LONG==64) +# define OFFSET(w) (((uint64_t) &w) & 0xFF) /* 256 byte offsets */ +#else +# define OFFSET(w) (((uint32_t) &w) & 0xFF) /* 256 byte offsets */ +#endif + +#define SCSI_BUS_32(scp) ((scp)->channel) +#define SCSI_TCN_32(scp) ((scp)->target) +#define SCSI_LUN_32(scp) ((scp)->lun) + +/****************************************************************************/ +/* LINUX - Loadable Module Functions. */ +/****************************************************************************/ + + +/************************************************************************* + * qla1280_set_info + * + * Description: + * Set parameters for the driver from the /proc filesystem. + * + * Returns: + *************************************************************************/ +int +qla1280_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) +{ + return (-ENOSYS); /* Currently this is a no-op */ +} + +/************************************************************************* + * qla1280_proc_info + * + * Description: + * Return information to handle /proc support for the driver. + * + * buffer - ptrs to a page buffer + * + * Returns: + *************************************************************************/ +#ifdef QLA1280_PROFILE +#define PROC_BUF (&qla1280_buffer[size]) +#define LUN_ID (targ_lun>>(MAX_T_BITS+MAX_L_BITS)),((targ_lun>>MAX_L_BITS)&0xf), targ_lun&0x7 +#endif +int +qla1280_proc_info ( char *buffer, char **start, off_t offset, int length, + int hostno, int inout) +{ +#ifdef QLA1280_PROFILE + struct Scsi_Host *host; + scsi_qla_host_t *ha; + int size = 0; + int targ_lun; + scsi_lu_t *up; + int no_devices; + + printk("Entering proc_info 0x%p,0x%lx,0x%x,0x%x\n",buffer,offset,length,hostno); + host = NULL; + /* find the host they want to look at */ + for(ha=qla1280_hostlist; (ha != NULL) && ha->host->host_no != hostno; ha=ha->next) + ; + + if (!ha) + { + size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + if (size > length) + { + return (size); + } + else + { + return (length); + } + } + + host = ha->host; + if (inout == TRUE) /* Has data been written to the file? */ + { + return (qla1280_set_info(buffer, length, host)); + } + + /* compute number of active devices */ + no_devices = 0; + for (targ_lun = 0; targ_lun < MAX_EQ; targ_lun++) + { + if( (up = ha->dev[targ_lun]) == NULL ) + continue; + no_devices++; + } + /* size = 112 * no_devices; */ + size = 4096; + /* round up to the next page */ + + /* + * if our old buffer is the right size use it otherwise + * allocate a new one. + */ + if (qla1280_buffer_size != size) + { + /* deallocate this buffer and get a new one */ + if (qla1280_buffer != NULL) + { + kfree(qla1280_buffer); + qla1280_buffer_size = 0; + } + qla1280_buffer = kmalloc(size, GFP_KERNEL); + } + if (qla1280_buffer == NULL) + { + size = sprintf(buffer, "qla1280 - kmalloc error at line %d\n", + __LINE__); + return size; + } + qla1280_buffer_size = size; + + size = 0; + size += sprintf(PROC_BUF, "Qlogic 1280/1080 SCSI driver version: "); /* 43 bytes */ + size += sprintf(PROC_BUF, "%5s, ", QLA1280_VERSION); /* 5 */ + size += sprintf(PROC_BUF, "Qlogic Firmware version: "); /* 25 */ + size += sprintf(PROC_BUF, "%2d.%2d.%2d",_firmware_version[0], /* 8 */ + ql12_firmware_version[1], + ql12_firmware_version[2]); + size += sprintf(PROC_BUF, "\n"); /* 1 */ + + size += sprintf(PROC_BUF, "SCSI Host Adapter Information: %s\n", QLBoardTbl[ha->devnum].bdName); + size += sprintf(PROC_BUF, "Request Queue = 0x%lx, Response Queue = 0x%lx\n", + ha->request_dma, + ha->response_dma); + size += sprintf(PROC_BUF, "Request Queue count= 0x%x, Response Queue count= 0x%x\n", + REQUEST_ENTRY_CNT, + RESPONSE_ENTRY_CNT); + size += sprintf(PROC_BUF,"Number of pending commands = 0x%lx\n", ha->actthreads); + size += sprintf(PROC_BUF,"Number of queued commands = 0x%lx\n", ha->qthreads); + size += sprintf(PROC_BUF,"Number of free request entries = %d\n",ha->req_q_cnt); + size += sprintf(PROC_BUF, "\n"); /* 1 */ + + size += sprintf(PROC_BUF, "Attached devices:\n"); + /* scan for all equipment stats */ + for (targ_lun = 0; targ_lun < MAX_EQ; targ_lun++) + { + if( (up = ha->dev[targ_lun]) == NULL ) + continue; + if( up->io_cnt == 0 ) + { + size += sprintf(PROC_BUF,"(%2d:%2d:%2d) No stats\n",LUN_ID); + continue; + } + /* total reads since boot */ + /* total writes since boot */ + /* total requests since boot */ + size += sprintf(PROC_BUF, "Total requests %ld,",up->io_cnt); + /* current number of pending requests */ + size += sprintf(PROC_BUF, "(%2d:%2d:%2d) pending requests %d,",LUN_ID,up->q_outcnt); + /* avg response time */ + size += sprintf(PROC_BUF, "Avg response time %ld%%,",(up->resp_time/up->io_cnt)*100); + + /* avg active time */ + size += sprintf(PROC_BUF, "Avg active time %ld%%\n",(up->act_time/up->io_cnt)*100); + } + + if (size >= qla1280_buffer_size) + { + printk(KERN_WARNING "qla1280: Overflow buffer in qla1280_proc.c\n"); + } + + if (offset > size - 1) + { + kfree(qla1280_buffer); + qla1280_buffer = NULL; + qla1280_buffer_size = length = 0; + *start = NULL; + } + else + { + *start = &qla1280_buffer[offset]; /* Start of wanted data */ + if (size - offset < length) + { + length = size - offset; + } + } +#endif + + return (length); +} + + +/************************************************************************** + * qla1280_detect + * This routine will probe for Qlogic 1280 SCSI host adapters. + * It returns the number of host adapters of a particular + * type that were found. It also initialize all data necessary for + * the driver. It is passed-in the host number, so that it + * knows where its first entry is in the scsi_hosts[] array. + * + * Input: + * template - pointer to SCSI template + * + * Returns: + * num - number of host adapters found. + **************************************************************************/ +int +qla1280_detect(Scsi_Host_Template *template) +{ + int num_hosts = 0; + struct Scsi_Host *host; + scsi_qla_host_t *ha, *cur_ha; + struct _qlaboards *bdp; + int i, j; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,95) + unsigned int piobase; + unsigned char pci_bus, pci_devfn, pci_irq; + config_reg_t *cfgp = 0; +#endif + device_reg_t *reg; + char *cp; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + struct pci_dev *pdev = NULL; +#else + int index; +#endif + + ENTER("qla1280_detect"); + +#ifdef CHECKSRBSIZE + if (sizeof(srb_t) > sizeof(Scsi_Pointer) ) + { + printk("Redefine SRB - its too big"); + return 0; + } +#endif + +#ifdef MODULE + DEBUG(sprintf(debug_buff,"DEBUG: qla1280_detect starts at address = %p\n",qla1280_detect);) + DEBUG(qla1280_print(debug_buff);) + /* + * If we are called as a module, the qla1280 pointer may not be null + * and it would point to our bootup string, just like on the lilo + * command line. IF not NULL, then process this config string with + * qla1280_setup + * + * Boot time Options + * To add options at boot time add a line to your lilo.conf file like: + * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}" + * which will result in the first four devices on the first two + * controllers being set to a tagged queue depth of 32. + */ + if(options) + qla1280_setup(options, NULL); + if(dummy_buffer[0] != 'P') + printk(KERN_WARNING "qla1280: Please read the file /usr/src/linux/drivers" + "/scsi/README.qla1280\n" + "qla1280: to see the proper way to specify options to the qla1280 " + "module\n" + "qla1280: Specifically, don't use any commas when passing arguments to\n" + "qla1280: insmod or else it might trash certain memory areas.\n"); +#endif + + if ((int) !pcibios_present()) + { + printk("scsi: PCI not present\n"); + return 0; + } /* end of IF */ + bdp = &QLBoardTbl[0]; + qla1280_hostlist = NULL; +#if 0 + template->proc_dir = &proc_scsi_qla1280; +#else + template->proc_name = "qla1280"; +#endif + + /* Try and find each different type of adapter we support */ + for( i=0; bdp->device_id != 0 && i < NUM_OF_ISP_DEVICES; i++, bdp++ ) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + while ((pdev = pci_find_device(QLA1280_VENDOR_ID, + bdp->device_id, pdev ) )) +#else + while (!(pcibios_find_device(QLA1280_VENDOR_ID, + bdp->device_id, + index++, &pci_bus, &pci_devfn)) ) +#endif + { + /* found a adapter */ + host = scsi_register(template, sizeof(scsi_qla_host_t)); + ha = (scsi_qla_host_t *) host->hostdata; + /* Clear our data area */ + for( j =0, cp = (char *)ha; j < sizeof(scsi_qla_host_t); j++) + *cp = 0; + /* Sanitize the information from PCI BIOS. */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + host->irq = pdev->irq; +/* this depends on release 2.3.18 */ + host->io_port = pdev->resource[0].start; +/* MRS host->io_port = (unsigned int) pdev->base_address[0]; */ + ha->pci_bus = pdev->bus->number; + ha->pci_device_fn = pdev->devfn; + ha->pdev = pdev; +#else + pcibios_read_config_byte(pci_bus, pci_devfn, OFFSET(cfgp->interrupt_line), &pci_irq); + pcibios_read_config_dword(pci_bus, pci_devfn, OFFSET(cfgp->base_port), &piobase); + host->irq = pci_irq; + host->io_port = (unsigned int) piobase; + ha->pci_bus = pci_bus; + ha->pci_device_fn = pci_devfn; +#endif + ha->device_id = bdp->device_id; + host->io_port &= PCI_BASE_ADDRESS_IO_MASK; + + ha->devnum = i; + host->io_port &= PCI_BASE_ADDRESS_IO_MASK; + if( qla1280_mem_alloc(ha) ) { + printk(KERN_INFO "qla1280: Failed to allocate memory for adapter\n"); + } + + ha->ports = bdp->numPorts; + ha->iobase = (device_reg_t *) host->io_port; + ha->host = host; + ha->host_no = host->host_no; + + /* load the F/W, read paramaters, and init the H/W */ + if (qla1280_initialize_adapter(ha)) + { + + printk(KERN_INFO "qla1280: Failed to initialized adapter\n"); + qla1280_mem_free(ha); + scsi_unregister(host); + continue; + } + + host->max_channel = bdp->numPorts-1; + ha->instance = num_hosts; + /* Register our resources with Linux */ + if( qla1280_register_with_Linux(ha, bdp->numPorts-1) ) { + printk(KERN_INFO "qla1280: Failed to register our resources\n"); + qla1280_mem_free(ha); + scsi_unregister(host); + continue; + } + + + reg = ha->iobase; + /* Disable ISP interrupts. */ + qla1280_disable_intrs(ha); + + /* Insure mailbox registers are free. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); + + /* Enable chip interrupts. */ + qla1280_enable_intrs(ha); + + /* Insert new entry into the list of adapters */ + ha->next = NULL; + if( qla1280_hostlist == NULL ) + { + cur_ha = qla1280_hostlist = ha; + } + else + { + cur_ha = qla1280_hostlist; + while( cur_ha->next != NULL ) + cur_ha = cur_ha->next; + cur_ha->next = ha; + } + num_hosts++; + } /* end of WHILE */ + } /* end of FOR */ + + LEAVE("qla1280_detect"); + return num_hosts; +} + +/************************************************************************** +* qla1280_register_with_Linux +* +* Description: +* Free the passed in Scsi_Host memory structures prior to unloading the +* module. +* +* Input: +* ha - pointer to host adapter structure +* maxchannels - MAX number of channels. +* +* Returns: +* 0 - Sucessfully reserved resources. +* 1 - Failed to reserved a resource. +**************************************************************************/ +STATIC uint8_t qla1280_register_with_Linux(scsi_qla_host_t *ha, uint8_t maxchannels) +{ + + struct Scsi_Host *host = ha->host; + + host->can_queue = 0xfffff; /* unlimited */ + host->cmd_per_lun = 1; + host->select_queue_depths = qla1280_select_queue_depth; + host->n_io_port = 0xFF; + host->base = (unsigned long) ha->mmpbase; + host->max_channel = maxchannels; + host->max_lun = MAX_LUNS-1; + host->unique_id = ha->instance; + host->max_id = MAX_TARGETS; + host->unique_id = ha->instance; + + /* set our host ID (need to do something about our two IDs) */ + host->this_id = ha->bus_settings[0].id; + /* Register the IRQ with Linux (sharable) */ + if ( request_irq(host->irq, qla1280_intr_handler, SA_INTERRUPT| SA_SHIRQ, "qla1280", ha)) + { + printk("qla1280 : Failed to reserved interrupt %d already in use\n", host->irq); + qla1280_mem_free(ha); + scsi_unregister(host); + return 1; + } + + /* Register the I/O space with Linux */ + if (check_region(host->io_port, 0xff)) + { + printk("qla1280 : Failed to reserved i/o region 0x%04lx-0x%04lx already in use\n", + host->io_port, host->io_port + 0xff); + free_irq(host->irq, NULL); + qla1280_mem_free(ha); + scsi_unregister(host); + return 1; + } + + request_region(host->io_port, 0xff, "qla1280"); + + return 0; +} + + +/************************************************************************** + * qla1280_release + * Free the passed in Scsi_Host memory structures prior to unloading the + * module. + **************************************************************************/ +int +qla1280_release(struct Scsi_Host *host) +{ + scsi_qla_host_t *ha = (scsi_qla_host_t *) host->hostdata; + + ENTER("qla1280_release"); + + if( !ha->flags.online ) + return(0); + + /* turn-off interrupts on the card */ + WRT_REG_WORD(&ha->iobase->ictrl, 0); + + /* Detach interrupts */ + if(host->irq) + free_irq(host->irq, ha); + + /* release io space registers */ + if( host->io_port ) + release_region(host->io_port, 0xff); + +#if MEMORY_MAPPED_IO + if(ha->mmpbase) + { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) + vfree((void *) (((unsigned long) ha->mmpbase) & PAGE_MASK)); +#else + iounmap((void *) (((unsigned long) ha->mmpbase) & PAGE_MASK)); +#endif + } +#endif /* MEMORY_MAPPED_IO */ + qla1280_mem_free(ha); + + ENTER("qla1280_release"); + return(0); +} + +/************************************************************************** + * qla1280_info + * Return a string describing the driver. + **************************************************************************/ +const char * +qla1280_info(struct Scsi_Host *host) +{ + static char qla1280_buffer[125]; + char *bp; + scsi_qla_host_t *ha; + qla_boards_t *bdp; + + bp = &qla1280_buffer[0]; + ha = (scsi_qla_host_t *)host->hostdata; + bdp = &QLBoardTbl[ha->devnum]; + memset(bp, 0, sizeof(qla1280_buffer)); + sprintf(bp, + "QLogic %sPCI to SCSI Host Adapter: bus %d device %d irq %d\n" + " Firmware version: %2d.%02d.%02d, Driver version %s", + (char *)&bdp->bdName[0], ha->pci_bus, (ha->pci_device_fn & 0xf8) >> 3, host->irq, + bdp->fwver[0],bdp->fwver[1],bdp->fwver[2], + QLA1280_VERSION); + return(bp); +} + +/************************************************************************** + * qla1200_queuecommand + * Queue a command to the controller. + * + * Note: + * The mid-level driver tries to ensures that queuecommand never gets invoked + * concurrently with itself or the interrupt handler (although the + * interrupt handler may call this routine as part of request-completion + * handling). Unfortunely, it sometimes calls the scheduler in interrupt + * context which is a big NO! NO!. + **************************************************************************/ +int +qla1280_queuecommand(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) +{ + scsi_qla_host_t *ha; + srb_t *sp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + struct Scsi_Host *host; + uint32_t b, t, l; + scsi_lu_t *q; + u_long handle; + + ENTER("qla1280_queuecommand"); + COMTRACE('C') + + host = cmd->host; + ha = (scsi_qla_host_t *) host->hostdata; + + /* send command to adapter */ + sp = (srb_t *) CMD_SP(cmd); + sp->cmd = cmd; + cmd->scsi_done = fn; + if (cmd->flags == 0) /* new command */ + { + sp->flags = 0; + } + + DEBUG5(qla1280_print_scsi_cmd(cmd)); + + /* Generate LU queue on bus, target, LUN */ + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + if((q = LU_Q(ha, b, t, l)) == NULL ) + { + DRIVER_LOCK + if( (q = (scsi_lu_t *)KMALLOC(sizeof(struct scsi_lu))) ) + { + LU_Q(ha, b, t, l) = q; + BZERO(q,sizeof(struct scsi_lu)); + DEBUG(sprintf(debug_buff,"Allocate new device queue 0x%x\n",q)); + DEBUG(qla1280_print(debug_buff)); + DRIVER_UNLOCK + } + else + { + CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16); + qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); + queue_task(&ha->run_qla_bh,&tq_scheduler); + ha->flags.dpc_sched = TRUE; + DRIVER_UNLOCK + return(0); + } + } + /* Set an invalid handle until we issue the command to ISP */ + /* then we will set the real handle value. */ + handle = INVALID_HANDLE; + CMD_HANDLE(cmd) = (unsigned char *)handle; + + /* Bookkeeping information */ + sp->r_start = jiffies; /* time the request was recieved */ + sp->u_start = 0; + + /* add the command to our queue */ + ha->qthreads++; + qla1280_putq_t(q,sp); + + DEBUG(sprintf(debug_buff,"qla1280_queuecmd: queue pid=%d, hndl=0x%x\n\r",cmd->pid,handle)); + DEBUG(qla1280_print(debug_buff)); + + /* send command to adapter */ + DRIVER_LOCK + if (q->q_outcnt == 0) + qla1280_restart_queues(ha); + DRIVER_UNLOCK + + + LEAVE("qla1280_queuecommand"); + return (0); +} + +/************************************************************************** + * qla1200_abort + * Abort the speciifed SCSI command(s). + **************************************************************************/ +int +qla1280_abort(Scsi_Cmnd *cmd) +{ + scsi_qla_host_t *ha; + srb_t *sp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + struct Scsi_Host *host; + uint32_t b, t, l; + scsi_lu_t *q; + int return_status = SCSI_ABORT_SUCCESS; + int found = 0; + int i; + u_long handle; + u_short data; + + ENTER("qla1280_abort"); + COMTRACE('A') + ha = (scsi_qla_host_t *) cmd->host->hostdata; + host = cmd->host; + DRIVER_LOCK + + /* Get the SCSI request ptr */ + sp = (srb_t *) CMD_SP(cmd); + handle = (u_long) CMD_HANDLE(cmd); + if (qla1280_verbose) + printk("scsi(%d): ABORT Command=0x%lx, handle=0x%lx\n",(int)ha->host_no,(long)cmd,handle); + + /* Check for pending interrupts. */ + if( handle == 0L ) + { + COMTRACE('a') + /* we never got this command */ + printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); + DRIVER_UNLOCK + return(SCSI_ABORT_NOT_RUNNING); /* no action - we don't have command */ + } + data = qla1280_debounce_register(&ha->iobase->istatus); + if( !(ha->flags.in_isr) && (data & RISC_INT) ) + { + /* put any pending command in done queue */ + qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + + handle = (u_long) CMD_HANDLE(cmd); + + /* Generate LU queue on bus, target, LUN */ + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + if((q = LU_Q(ha, b, t, l)) == NULL ) + { + COMTRACE('a') + /* No lun queue -- command must not be active */ + DRIVER_UNLOCK + printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the specified device\n",(int)b,(int)t,(int)l); + return(SCSI_ABORT_NOT_RUNNING); /* no action - we don't have command */ + } + +#if AUTO_ESCALATE_ABORT + if ( (sp->flags & SRB_ABORTED) ) + { + DRIVER_UNLOCK + DEBUG(qla1280_print("qla1280_abort: Abort escalayted - returning SCSI_ABORT_SNOOZE.\n\r")); + return(SCSI_ABORT_SNOOZE); + } +#endif + + if ( (sp->flags & SRB_ABORT_PENDING) ) + { + COMTRACE('a') + DRIVER_UNLOCK + if( qla1280_verbose ) + printk("scsi(): Command has a pending abort message - ABORT_PENDING.\n"); + DEBUG(qla1280_print("qla1280: Command has a pending abort message - ABORT_PENDING.\n\r")); + return(SCSI_ABORT_PENDING); + } + +#if STOP_ON_ABORT + printk("Scsi layer issued a ABORT command= 0x%x\n",(int)cmd); + DEBUG2(qla1280_print_scsi_cmd(cmd)); +#endif + + ha->flags.in_abort = TRUE; + /* + * Normally, would would need to search our queue for the specified command + * but; since our sp contains the cmd ptr, we can just remove it from our + * LUN queue. + */ + if( !(sp->flags&SRB_SENT) ) + { + found++; + if( qla1280_verbose ) + printk("scsi(): Command returned from queue aborted.\n"); + DEBUG(qla1280_print("qla1280: Command returned from queue aborted.\n\r")); + /* Remove srb from SCSI LU queue. */ + qla1280_removeq(q, sp); + sp->flags |= SRB_ABORTED; + CMD_RESULT(cmd) = DID_ABORT << 16; + qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); + return_status = SCSI_ABORT_SUCCESS; + } + else + { /* find the command in our active list */ + for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) + { + if( sp == ha->outstanding_cmds[i] ) + { + found++; + DEBUG(qla1280_print("qla1280: RISC aborting command.\n\r")); + qla1280_abort_command(ha,sp); + return_status = SCSI_ABORT_PENDING; + break; + } + } + } + +#if STOP_ON_ABORT + qla1280_panic("qla1280_abort",ha->host); +#endif + if ( found == 0 ) + return_status = SCSI_ABORT_NOT_RUNNING; /* no action - we don't have command */ + + DEBUG(sprintf(debug_buff, "qla1280_abort: Aborted status returned = 0x%x.\n\r",return_status)); + DEBUG(qla1280_print(debug_buff)); + + if( ha->done_q_first ) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + if ( found ) + { + qla1280_restart_queues(ha); + } + ha->flags.in_abort = FALSE; + DRIVER_UNLOCK + + LEAVE("qla1280_abort"); + COMTRACE('a') + return(return_status); +} + +/************************************************************************** + * qla1200_reset + * The reset function will reset the SCSI bus and abort any executing + * commands. + * + * Input: + * cmd = Linux SCSI command packet of the command that cause the + * bus reset. + * flags = SCSI bus reset option flags (see scsi.h) + * + * Returns: + * DID_RESET in cmd.host_byte of aborted command(s) + * + * Note: + * Resetting the bus always succeeds - is has to, otherwise the + * kernel will panic! Try a surgical technique - sending a BUS + * DEVICE RESET message - on the offending target before pulling + * the SCSI bus reset line. + **************************************************************************/ +int +qla1280_reset(Scsi_Cmnd *cmd, unsigned int flags) +{ + scsi_qla_host_t *ha; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + uint32_t b, t, l; + srb_t *sp; + typedef enum + { + ABORT_DEVICE = 1, + DEVICE_RESET = 2, + BUS_RESET = 3, + ADAPTER_RESET= 4, + RESET_DELAYED= 5, + FAIL = 6 + } action_t; + action_t action = ADAPTER_RESET; + u_short data; + scsi_lu_t *q; + int result; + + + ENTER("qla1280_reset"); + COMTRACE('R') + if (qla1280_verbose) + printk("scsi(): Resetting Cmnd=0x%lx, Handle=0x%lx, flags=0x%x\n",(long)cmd,(long)CMD_HANDLE(cmd),flags); + if ( cmd == NULL ) + { + printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd " + "pointer, failing.\n"); + return(SCSI_RESET_SNOOZE); + } + ha = (scsi_qla_host_t *) cmd->host->hostdata; + sp = (srb_t *) CMD_SP(cmd); + +#if STOP_ON_RESET + qla1280_panic("qla1280_reset",ha->host); +#endif + + DRIVER_LOCK + /* Check for pending interrupts. */ + data = qla1280_debounce_register(&ha->iobase->istatus); + if( !(ha->flags.in_isr) && (data & RISC_INT) ) + { + qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + } + DRIVER_UNLOCK + + /* + * Determine the suggested action that the mid-level driver wants + * us to perform. + */ + if( CMD_HANDLE(cmd) == (unsigned char *) 0 ) + { + /* + * if mid-level driver called reset with a orphan SCSI_Cmnd + * (i.e. a command that's not pending ), so perform the + * function specified. + */ + if( (flags & SCSI_RESET_SUGGEST_HOST_RESET) ) + action = ADAPTER_RESET; + else + action = BUS_RESET; + } + else + { /* + * Mid-level driver has called reset with this SCSI_Cmnd and + * its pending. + */ + if( flags & SCSI_RESET_SUGGEST_HOST_RESET ) + action = ADAPTER_RESET; + else if( flags & SCSI_RESET_SUGGEST_BUS_RESET ) + action = BUS_RESET; + else + action = DEVICE_RESET; + } + + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + q = LU_Q(ha, b, t, l); + +#if AUTO_ESCALATE_RESET + if ( (action & DEVICE_RESET) && (q->q_flag & QLA1280_QRESET) ) + { + printk(KERN_INFO "qla1280(%d): Bus device reset already sent to " "device, escalating.\n", (int)ha->host_no); + action = BUS_RESET; + } + if ( (action & DEVICE_RESET) && (sp->flags & SRB_ABORT_PENDING) ) + { + printk(KERN_INFO "qla1280(%d):Have already attempted to reach " "device with abort device\n", (int)ha->host_no); + printk(KERN_INFO "qla1280(%d):message, will escalate to BUS " "RESET.\n",(int) ha->host_no); + action = BUS_RESET; + } +#endif + + /* + * By this point, we want to already know what we are going to do, + * so we only need to perform the course of action. + */ + DRIVER_LOCK + result = SCSI_RESET_ERROR; + switch (action) + { + case FAIL: + break; + + case RESET_DELAYED: + result = SCSI_RESET_PENDING; + break; + + case ABORT_DEVICE: + ha->flags.in_reset = TRUE; + if (qla1280_verbose) + printk(KERN_INFO "scsi(%d:%d:%d:%d): Queueing abort device command.\n", (int)ha->host_no,(int)b,(int)t,(int)l); + qla1280_abort_queue_single(ha,b,t,l,DID_ABORT); + if( qla1280_abort_device(ha, b, t, l) == 0) + result = SCSI_RESET_PENDING; + break; + + case DEVICE_RESET: + if (qla1280_verbose) + printk(KERN_INFO "scsi(%d:%d:%d:%d): Queueing device reset command.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + ha->flags.in_reset = TRUE; + for (l = 0; l < MAX_LUNS; l++) + qla1280_abort_queue_single(ha,b,t,l,DID_ABORT); + if( qla1280_device_reset(ha, b, t) == 0 ) + result = SCSI_RESET_PENDING; + q->q_flag |= QLA1280_QRESET; + break; + + case BUS_RESET: + if (qla1280_verbose) + printk(KERN_INFO "qla1280(%d:%d:%d:%d): Issuing BUS DEVICE RESET.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + ha->flags.in_reset = TRUE; + for (t = 0; t < MAX_TARGETS; t++) + for (l = 0; l < MAX_LUNS; l++) + qla1280_abort_queue_single(ha,b,t,l,DID_RESET); + qla1280_bus_reset(ha, b); + /* + * The bus reset routine returns all the outstanding commands back + * with "DID_RESET" in the status field after a short delay + * by the firmware. If the mid-level time out the SCSI reset before + * our delay we may need to ignore it. + */ + /* result = SCSI_RESET_PENDING | SCSI_RESET_BUS_RESET; */ + result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; + mdelay(4 * 1000); barrier(); + if( flags & SCSI_RESET_SYNCHRONOUS ) + { + CMD_RESULT(cmd) = (int) (DID_BUS_BUSY << 16); + (*(cmd)->scsi_done)(cmd); + } + /* ha->reset_start = jiffies; */ + break; + + case ADAPTER_RESET: + default: + if (qla1280_verbose) + { + printk(KERN_INFO "scsi(%d:%d:%d:%d): Issued an ADAPTER RESET.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + printk(KERN_INFO "scsi(%d:%d:%d:%d): I/O processing will continue automatically.\n",(int) ha->host_no,(int)b,(int)t,(int)l); + } + ha->flags.reset_active = TRUE; + /* + * We restarted all of the commands automatically, so the mid-level code can expect + * completions momentitarily. + */ + if( qla1280_abort_isp(ha) == 0 ) + result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; + + ha->flags.reset_active = FALSE; + } + + if( ha->done_q_first ) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + qla1280_restart_queues(ha); + ha->flags.in_reset = FALSE; + +DRIVER_UNLOCK + DEBUG(printk("RESET returning %d\n", result)); + + COMTRACE('r') + LEAVE("qla1280_reset"); + return( result ); +} + +/************************************************************************** + * qla1200_biosparam + * Return the disk geometry for the given SCSI device. + **************************************************************************/ +int +qla1280_biosparam(Disk *disk, kdev_t dev, int geom[]) +{ + int heads, sectors, cylinders; + + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + if (cylinders > 1024) + { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + /* if (cylinders > 1023) + cylinders = 1023; */ + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return (0); +} +/************************************************************************** + * qla1280_intr_handler + * Handles the H/W interrupt + **************************************************************************/ +void qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + scsi_qla_host_t *ha; + u_short data; + device_reg_t *reg; + + ENTER_INTR("qla1280_intr_handler"); + COMTRACE('I') + ha = (scsi_qla_host_t *) dev_id; + if(!ha) + { + printk(KERN_INFO "scsi(): Interrupt with NULL host ptr\n"); + COMTRACE('X') + return; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95) + spin_lock_irqsave(&io_request_lock, cpu_flags); + if(test_and_set_bit(QLA1280_IN_ISR_BIT, &ha->flags)) + { + COMTRACE('X') + return; + } + ha->isr_count++; + reg = ha->iobase; + /* disable our interrupt. */ + WRT_REG_WORD(®->ictrl, 0); + data = qla1280_debounce_register(®->istatus); + /* Check for pending interrupts. */ + if ( !(data & RISC_INT) ) + { + /* spurious interrupts can happen legally */ + DEBUG(printk("scsi(%d): Spurious interrupt - ignoring\n",(int)ha->host_no)); + COMTRACE('X') + } + else + qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + if (ha->done_q_first) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + clear_bit(QLA1280_IN_ISR_BIT, &ha->flags); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) */ + + if( test_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags) ) + { + COMTRACE('X') + printk(KERN_INFO "scsi(%d): Already in interrupt - returning \n", (int)ha->host_no); + return; + } + set_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags); + ha->isr_count++; + reg = ha->iobase; + /* disable our interrupt. */ + WRT_REG_WORD(®->ictrl, 0); + + data = qla1280_debounce_register(®->istatus); + /* Check for pending interrupts. */ + if ( !(data & RISC_INT) ) + { + /* spurious interrupts can happen legally */ + DEBUG(printk("scsi(%d): Spurious interrupt - ignoring\n",(int)ha->host_no)); + COMTRACE('X') + } + else + qla1280_isr(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + /* if no work to do then call the SCSI mid-level right away */ + if( ha->done_q_first ) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + + /* Schedule the DPC routine */ + if (ha->flags.isp_abort_needed || ha->flags.reset_marker || + ha->done_q_first ) + { + ha->run_qla_bh.data = (void *) ha; + ha->run_qla_bh.routine = qla1280_do_dpc; + + COMTRACE('P') + queue_task_irq(&ha->run_qla_bh,&tq_scheduler); + ha->flags.dpc_sched = TRUE; + } + clear_bit(QLA1280_IN_ISR_BIT, (int *)&ha->flags); +#endif + /* enable our interrupt. */ + WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC); + + COMTRACE('i') + LEAVE_INTR("qla1280_intr_handler"); +} + +/************************************************************************** + * qla1280_do_dpc + * + * Description: + * This routine is a task that is schedule by the interrupt handler + * to perform the background processing for interrupts. We put it + * on a task queue that is consumed whenever the scheduler runs; that's + * so you can do anything (i.e. put the process to sleep etc). In fact, the + * mid-level tries to sleep when it reaches the driver threshold + * "host->can_queue". This can cause a panic if we were in our interrupt + * code . + **************************************************************************/ +void qla1280_do_dpc(void *p) +{ + scsi_qla_host_t *ha = (scsi_qla_host_t *) p; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + + COMTRACE('p') +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + spin_lock_irqsave(&io_request_lock, cpu_flags); +#endif + if (ha->flags.isp_abort_needed) + qla1280_abort_isp(ha); + + if (ha->flags.reset_marker) + qla1280_rst_aen(ha); + + if (ha->done_q_first) + qla1280_done(ha, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + ha->flags.dpc_sched = FALSE; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +#endif +} + +/************************************************************************** + * qla1280_device_queue_depth + * + * Description: + * Determines the queue depth for a given device. There are two ways + * a queue depth can be obtained for a tagged queueing device. One + * way is the default queue depth which is determined by whether + * If it is defined, then it is used + * as the default queue depth. Otherwise, we use either 4 or 8 as the + * default queue depth (dependent on the number of hardware SCBs). + **************************************************************************/ +STATIC void qla1280_device_queue_depth(scsi_qla_host_t *p, Scsi_Device *device) +{ + int default_depth = 3; + int bus = device->channel; + int target = device->id; + + device->queue_depth = default_depth; + + if (device->tagged_supported && + (p->bus_settings[bus].qtag_enables & (BIT_0 << target)) ) + { + device->tagged_queue = 1; + device->current_tag = 0; + device->queue_depth = p->bus_settings[bus].hiwat; + /* device->queue_depth = 20; */ + printk(KERN_INFO "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue depth %d.\n", + (int)p->host_no, device->channel, device->id, + device->lun, device->queue_depth); + } + qla12160_get_target_parameters(p, bus, target, device->lun); + +} + +/************************************************************************** + * qla1280_select_queue_depth + * + * Sets the queue depth for each SCSI device hanging off the input + * host adapter. We use a queue depth of 2 for devices that do not + * support tagged queueing. + **************************************************************************/ +STATIC void +qla1280_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs) +{ + Scsi_Device *device; + scsi_qla_host_t *p = (scsi_qla_host_t *) host->hostdata; + + ENTER("qla1280_select_queue_depth"); + for (device = scsi_devs; device != NULL; device = device->next) + { + if (device->host == host) + qla1280_device_queue_depth(p, device); + } + LEAVE("qla1280_select_queue_depth"); +} + +/*--------------------------** +** Driver Support Routines ** +**--------------------------*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +/* + * mdelay + * Delay in milliseconds + * + * Input: + * milliseconds = delay + */ +STATIC inline void mdelay(int milliseconds) +{ + int i; + + for(i=0; is_next)) + *done_q_last = NULL; + else + (*done_q_first)->s_prev = NULL; + cmd = sp->cmd; + b = SCSI_BUS_32(cmd); + t = SCSI_TCN_32(cmd); + l = SCSI_LUN_32(cmd); + q = LU_Q(ha, b, t, l); + + /* Decrement outstanding commands on device. */ + if (q->q_outcnt) + q->q_outcnt--; + if (q->q_outcnt < ha->bus_settings[b].hiwat) + { + q->q_flag &= ~QLA1280_QBUSY; + } + + q->resp_time += jiffies - sp->r_start; /* Lun bookkeeping information */ + q->act_time += jiffies - sp->u_start; + q->io_cnt++; + if( sp->dir & BIT_5 ) + q->r_cnt++; + else + q->w_cnt++; + + switch ( (CMD_RESULT(cmd)>>16)) + { + case DID_RESET: + q->q_flag &= ~QLA1280_QRESET; + /* Issue marker command. */ + qla1280_marker(ha, b, t, 0, MK_SYNC_ID); + break; + case DID_ABORT: + sp->flags &= ~SRB_ABORT_PENDING; + sp->flags |= SRB_ABORTED; + if (sp->flags & SRB_TIMEOUT) + CMD_RESULT(sp->cmd)= DID_TIME_OUT << 16; + break; + default: + break; + } + + /* Call the mid-level driver interrupt handler */ + CMD_HANDLE(sp->cmd) = (unsigned char *) 0; + ha->actthreads--; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + sti(); + (*(cmd)->scsi_done)(cmd); + cli(); +#else + (*(cmd)->scsi_done)(cmd); +#endif + qla1280_next(ha, q, b); + } + DRIVER_UNLOCK + + + COMTRACE('d') + LEAVE("qla1280_done"); +} + +/* + * Translates a ISP error to a Linux SCSI error + */ +STATIC int qla1280_return_status( sts_entry_t *sts, Scsi_Cmnd *cp) +{ + int host_status = DID_ERROR; +#if DEBUG_QLA1280_INTR + STATIC char *reason[] = + { + "DID_OK", + "DID_NO_CONNECT", + "DID_BUS_BUSY", + "DID_TIME_OUT", + "DID_BAD_TARGET", + "DID_ABORT", + "DID_PARITY", + "DID_ERROR", + "DID_RESET", + "DID_BAD_INTR" + }; +#endif /* DEBUG_QLA1280_INTR */ + + ENTER("qla1280_return_status"); + +#if DEBUG_QLA1280_INTR + /* + DEBUG(printk("qla1280_return_status: compl status = 0x%04x\n", sts->comp_status)); + */ +#endif + switch(sts->comp_status) + { + case CS_COMPLETE: + host_status = DID_OK; + break; + case CS_INCOMPLETE: + if (!(sts->state_flags & SF_GOT_BUS)) + host_status = DID_NO_CONNECT; + else if (!(sts->state_flags & SF_GOT_TARGET)) + host_status = DID_BAD_TARGET; + else if (!(sts->state_flags & SF_SENT_CDB)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_STATUS)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_SENSE)) + host_status = DID_ERROR; + break; + case CS_RESET: + host_status = DID_RESET; + break; + case CS_ABORTED: + host_status = DID_ABORT; + break; + case CS_TIMEOUT: + host_status = DID_TIME_OUT; + break; + case CS_DATA_OVERRUN: +#ifdef QL_DEBUG_LEVEL_2 + printk("Data overrun 0x%x\n",(int)sts->residual_length); + qla1280_print( + "\n\rqla1280_isr: response packet data\n\r"); + qla1280_dump_buffer((caddr_t)sts, + RESPONSE_ENTRY_SIZE); +#endif + host_status = DID_ERROR; + break; + case CS_DATA_UNDERRUN: + if ( (CMD_XFRLEN(cp) - sts->residual_length) < cp->underflow) + { + printk("scsi: Underflow detected - retrying command.\n"); + host_status = DID_ERROR; + } + else + host_status = DID_OK; + break; + default: + host_status = DID_ERROR; + break; + } + +#if DEBUG_QLA1280_INTR + sprintf(debug_buff, "qla1280 ISP status: host status (%s) scsi status %x\n\r", reason[host_status], sts->scsi_status); + qla1280_print(debug_buff); +#endif + + LEAVE("qla1280_return_status"); + + return (sts->scsi_status & 0xff) | (host_status << 16); +} + +/* + * qla1280_done_q_put + * Place SRB command on done queue. + * + * Input: + * sp = srb pointer. + * done_q_first = done queue first pointer. + * done_q_last = done queue last pointer. + */ +STATIC void +qla1280_done_q_put(srb_t *sp, srb_t **done_q_first, srb_t **done_q_last) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_put_done_q"); +#endif + /* Place block on done queue */ + DRIVER_LOCK + sp->s_next = NULL; + sp->s_prev = *done_q_last; + if (!*done_q_first) + *done_q_first = sp; + else + (*done_q_last)->s_next = sp; + *done_q_last = sp; + + DRIVER_UNLOCK +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_put_done_q"); +#endif +} + +/* + * qla1280_next + * Retrieve and process next job in the queue. + * + * Input: + * ha = adapter block pointer. + * q = SCSI LU pointer. + * b = SCSI bus number. + * SCSI_LU_Q lock must be already obtained and no other locks. + * + * Output: + * Releases SCSI_LU_Q upon exit. + */ +STATIC void +qla1280_next(scsi_qla_host_t *ha, scsi_lu_t *q, uint8_t b) +{ + srb_t *sp; + uint32_t cnt; + uint8_t status; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + + ENTER("qla1280_next"); + + DRIVER_LOCK + while ( ((sp = q->q_first) != NULL) && /* we have a queue pending */ + !(q->q_flag & QLA1280_QBUSY) && /* device not busy */ + !ha->flags.abort_isp_active && /* not resetting the adapter */ + !(q->q_flag & QLA1280_QSUSP) ) /* device not suspended */ + { + /* Remove srb from SCSI LU queue. */ + qla1280_removeq(q, sp); + + DEBUG(sprintf(debug_buff,"starting request 0x%p<-(0x%p)\n\r",q,sp)); + DEBUG(qla1280_print(debug_buff)); + { + /* Set busy flag if reached high water mark. */ + q->q_outcnt++; + if (q->q_outcnt >= ha->bus_settings[b].hiwat) + q->q_flag |= QLA1280_QBUSY; + +#if QLA1280_64BIT_SUPPORT + if (ha->flags.enable_64bit_addressing) + status = qla1280_64bit_start_scsi(ha, sp); + else +#endif + status = qla1280_32bit_start_scsi(ha, sp); + + if (status) /* if couldn't start the request */ + { + if (q->q_outcnt == 1) + { + /* Release SCSI LU queue specific lock */ + QLA1280_SCSILU_UNLOCK(q); + + /* Wait for 30 sec for command to be accepted. */ + for (cnt = 6000000; cnt; cnt--) + { +#if QLA1280_64BIT_SUPPORT + if (ha->flags.enable_64bit_addressing) + status = qla1280_64bit_start_scsi(ha, sp); + else +#endif + status = qla1280_32bit_start_scsi(ha, sp); + + if (!status) + { + break; + } + + /* Go check for pending interrupts. */ + qla1280_poll(ha); + + SYS_DELAY(5); /* 10 */ + } + if (!cnt) + { + /* Set timeout status */ + CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16; + +#if WATCHDOGTIMER + /* Remove command from watchdog queue. */ + if (sp->flags & SRB_WATCHDOG) + qla1280_timeout_remove(ha, sp); +#endif + COMTRACE('M') + CMD_HANDLE(sp->cmd) = (unsigned char *) 0; + + /* Call the mid-level driver interrupt handler */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + sti(); + (*(sp->cmd)->scsi_done)(sp->cmd); + cli(); +#else + (*(sp->cmd)->scsi_done)(sp->cmd); +#endif + + /* Acquire LU queue specific lock */ + QLA1280_SCSILU_LOCK(q); + + if (q->q_outcnt) + q->q_outcnt--; + } + else + /* Acquire LU queue specific lock */ + QLA1280_SCSILU_LOCK(q); + } + else + { /* Place request back on top of device queue. */ + qla1280_putq_t(q, sp); + + if (q->q_outcnt) + q->q_outcnt--; + if (q->q_outcnt < ha->bus_settings[b].hiwat) + q->q_flag &= ~QLA1280_QBUSY; + break; + } + } + } + } + DRIVER_UNLOCK + + /* Release SCSI LU queue specific lock */ + QLA1280_SCSILU_UNLOCK(q); + + LEAVE("qla1280_next"); +} + +/* + * qla1280_putq_t + * Add the standard SCB job to the top of standard SCB commands. + * + * Input: + * q = SCSI LU pointer. + * sp = srb pointer. + * SCSI_LU_Q lock must be already obtained. + */ +STATIC void +qla1280_putq_t(scsi_lu_t *q, srb_t *sp) +{ + srb_t *srb_p; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_putq_t"); +#endif + DRIVER_LOCK + DEBUG(sprintf(debug_buff,"Adding to device 0x%p<-(0x%p)\n\r",q,sp)); + DEBUG(qla1280_print(debug_buff)); + sp->s_next = NULL; + if (!q->q_first) /* If queue empty */ + { + sp->s_prev = NULL; + q->q_first = sp; + q->q_last = sp; + } + else + { + srb_p = q->q_first; + while (srb_p ) + srb_p = srb_p->s_next; + + if (srb_p) + { + sp->s_prev = srb_p->s_prev; + if (srb_p->s_prev) + srb_p->s_prev->s_next = sp; + else + q->q_first = sp; + srb_p->s_prev = sp; + sp->s_next = srb_p; + } + else + { + sp->s_prev = q->q_last; + q->q_last->s_next = sp; + q->q_last = sp; + } + } + + DRIVER_UNLOCK +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_putq_t"); +#endif +} + +/* + * qla1280_removeq + * Function used to remove a command block from the + * LU queue. + * + * Input: + * q = SCSI LU pointer. + * sp = srb pointer. + * SCSI_LU_Q lock must be already obtained. + */ +STATIC void +qla1280_removeq(scsi_lu_t *q, srb_t *sp) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + DEBUG(sprintf(debug_buff,"Removing from device_q (0x%p)->(0x%p)\n\r",q,sp)); + DEBUG(qla1280_print(debug_buff)); + DRIVER_LOCK + if (sp->s_prev) + { + if ((sp->s_prev->s_next = sp->s_next) != NULL) + sp->s_next->s_prev = sp->s_prev; + else + q->q_last = sp->s_prev; + } + else if (!(q->q_first = sp->s_next)) + q->q_last = NULL; + else + q->q_first->s_prev = NULL; + DRIVER_UNLOCK +} + +/* +* qla1280_mem_alloc +* Allocates adapter memory. +* +* Returns: +* 0 = success. +* 1 = failure. +*/ +STATIC uint8_t +qla1280_mem_alloc(scsi_qla_host_t *ha) +{ + + uint8_t status = 1; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_mem_alloc"); +#endif + +#ifdef DYNAMIC_MEM_ALLOC + ha->request_ring = qla1280_alloc_phys(REQUEST_ENTRY_SIZE * REQUEST_ENTRY_CNT, + &ha->request_dma); + if(ha->request_ring) { + ha->response_ring = qla1280_alloc_phys(RESPONSE_ENTRY_SIZE * RESPONSE_ENTRY_CNT, + &ha->response_dma); + if(ha->response_ring) { + status = 0; + } + } +#else + ha->request_ring = &ha->req[0]; + ha->request_dma = VIRT_TO_BUS(&ha->req[0]); + ha->response_ring = &ha->res[0]; + ha->response_dma = VIRT_TO_BUS(&ha->res[0]); + status = 0; +#endif + + if(status) { +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_mem_alloc: **** FAILED ****\n"); +#endif + } +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_mem_alloc"); +#endif + return(status); +} + +/* + * qla1280_mem_free + * Frees adapter allocated memory. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_mem_free(scsi_qla_host_t *ha) +{ + scsi_lu_t *q; + uint32_t b, t, l; + + ENTER("qlc1280_mem_free"); + if (ha) + { + /* Free device queues. */ + for (b = 0; b < MAX_BUSES; b++) + { + q = LU_Q(ha, b, ha->bus_settings[b].id, 0); + for (t = 0; t < MAX_TARGETS; t++) + for (l = 0; l < MAX_LUNS; l++) + if (LU_Q(ha, b, t, l) != NULL && LU_Q(ha, b, t, l) != q) + KMFREE(LU_Q(ha, b, t, l),sizeof(struct scsi_lu)); + KMFREE(q, sizeof(struct scsi_lu)); + } + for( b =0; b < MAX_EQ; b++ ) + ha->dev[b] = (scsi_lu_t *)NULL; + } + + LEAVE("qlc1280_mem_free"); +} + + + + +/****************************************************************************/ +/* QLogic ISP1280 Hardware Support Functions. */ +/****************************************************************************/ + + /* + * qla2100_enable_intrs + * qla2100_disable_intrs + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * None + */ + static inline void qla1280_enable_intrs(scsi_qla_host_t *ha) { + device_reg_t *reg; + + reg = ha->iobase; + ha->flags.interrupts_on = 1; + /* enable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, (ISP_EN_INT+ ISP_EN_RISC)); + } + + static inline void qla1280_disable_intrs(scsi_qla_host_t *ha) { + device_reg_t *reg; + + reg = ha->iobase; + ha->flags.interrupts_on = 0; + /* disable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, 0); + } + +/* + * qla1280_initialize_adapter + * Initialize board. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_initialize_adapter(scsi_qla_host_t *ha) +{ + device_reg_t *reg; + uint8_t status; + /* uint8_t cnt; */ + uint8_t b; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_initialize_adapter"); +#endif + + /* Clear adapter flags. */ + ha->flags.online = FALSE; + ha->flags.isp_abort_needed = FALSE; + ha->flags.disable_host_adapter = FALSE; + ha->flags.reset_active = FALSE; + ha->flags.abort_isp_active = FALSE; + ha->flags.watchdog_enabled = FALSE; + + DEBUG(printk("Configure PCI space for adapter...\n")); + if (!(status = qla1280_pci_config(ha))) + { + reg = ha->iobase; + + /* Disable ISP interrupts. */ + WRT_REG_WORD(®->ictrl, 0); + + /* Insure mailbox registers are free. */ + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); + + /* If firmware needs to be loaded */ + if (qla1280_verbose) + printk("scsi(%d): Determining if RISC is loaded...\n",(int)ha->host_no); + if (qla1280_isp_firmware(ha)) + { + if (qla1280_verbose) + printk("scsi(%d): Verifying chip...\n",(int)ha->host_no); + if (!(status = qla1280_chip_diag(ha))) + { + if (qla1280_verbose) + printk("scsi(%d): Setup chip...\n",(int)ha->host_no); + status = qla1280_setup_chip(ha); + } + } + + if (!status) + { + /* Setup adapter based on NVRAM parameters. */ + if (qla1280_verbose) + printk("scsi(%d): Configure NVRAM parameters...\n",(int)ha->host_no); + qla1280_nvram_config(ha); + + if (!ha->flags.disable_host_adapter && + !qla1280_init_rings(ha)) + { + /* Issue SCSI reset. */ + for (b = 0; b < ha->ports; b++) + if (!ha->bus_settings[b].disable_scsi_reset) + { + /* dg 03/13 if we can't reset twice then bus is dead */ + if( qla1280_bus_reset(ha, b) ) + if( qla1280_bus_reset(ha, b) ) + { + ha->bus_settings[b].scsi_bus_dead = TRUE; + } + } + + do + { + /* Issue marker command. */ + ha->flags.reset_marker = FALSE; + for (b = 0; b < ha->ports; b++) + { + ha->bus_settings[b].reset_marker = FALSE; + qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL); + } + }while (ha->flags.reset_marker); + + ha->flags.online = TRUE; + + /* Enable host adapter target mode. */ + for (b = 0; b < ha->ports; b++) + { + if (!(status = qla1280_enable_tgt(ha, b))) + { + /* for (cnt = 0; cnt < MAX_LUNS; cnt++) + { + qla1280_enable_lun(ha, b, cnt); + qla1280_poll(ha); + }*/ + } + else + break; + } + } + else + status = 1; + } + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_initialize_adapter: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_initialize_adapter"); +#endif + return(status); +} + +/* + * qla1280_enable_tgt + * Enable target mode. + * + * Input: + * ha = adapter block pointer. + * b = SCSI bus number. + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_enable_tgt(scsi_qla_host_t *ha, uint8_t b) +{ + uint8_t status = 0; + /* uint16_t mb[MAILBOX_REGISTER_COUNT]; */ + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_enable_tgt: entered\n\r"); +#endif + + /* Enable target mode. */ + /* + mb[0] = MBC_ENABLE_TARGET_MODE; + mb[1] = BIT_15; + mb[2] = (uint16_t)(b << 15); + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_enable_tgt: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_enable_tgt: exiting normally\n\r"); +#endif + return(status); +} + +/* + * ISP Firmware Test + * Checks if present version of RISC firmware is older than + * driver firmware. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = firmware does not need to be loaded. + */ +STATIC uint8_t +qla1280_isp_firmware(scsi_qla_host_t *ha) +{ + nvram_t *nv = (nvram_t *)ha->response_ring; + uint16_t *wptr; + uint8_t chksum; + uint8_t cnt; + uint8_t status = 0; /* dg 2/27 always loads RISC */ + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + ENTER("qla1280_isp_firmware"); + + /* Verify valid NVRAM checksum. */ + wptr = (uint16_t *)ha->response_ring; + DEBUG(printk("qla1280_isp_firmware: Reading NVRAM\n")); + chksum = 0; + for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++) + { + *wptr = qla1280_get_nvram_word(ha, cnt); + chksum += (uint8_t)*wptr; + chksum += (uint8_t)(*wptr >> 8); + wptr++; + } + DEBUG(printk("qla1280_isp_firmware: Completed Reading NVRAM\n")); + +#if defined(QL_DEBUG_LEVEL_3) + sprintf(debug_buff,"qla1280_isp_firmware: NVRAM Magic ID= %c %c %c\n\r",(char *) nv->id[0],nv->id[1],nv->id[2]); + qla1280_print(debug_buff); +#endif + + /* Bad NVRAM data, load RISC code. */ + if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || + nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) + { + printk(KERN_INFO "qla1280_isp_firmware: Bad checksum or magic number or version in NVRAM.\n"); + ha->flags.disable_risc_code_load = FALSE; + } + else + ha->flags.disable_risc_code_load = nv->cntr_flags_1.disable_loading_risc_code; + + if (ha->flags.disable_risc_code_load) + { +#if defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_isp_firmware: Telling RISC to verify checksum of loaded BIOS code.\n\r"); +#endif + /* Verify checksum of loaded RISC code. */ + mb[0] = MBC_VERIFY_CHECKSUM; + /* mb[1] = ql12_risc_code_addr01; */ + mb[1] = *QLBoardTbl[ha->devnum].fwstart; + + if (!(status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]))) + { + /* Start firmware execution. */ +#if defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_isp_firmware: Startng F/W execution.\n\r"); +#endif + mb[0] = MBC_EXECUTE_FIRMWARE; + /* mb[1] = ql12_risc_code_addr01; */ + mb[1] = *QLBoardTbl[ha->devnum].fwstart; + qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + } + else + printk(KERN_INFO "qla1280: RISC checksum failed.\n"); + } + else + { + DEBUG(printk("qla1280: NVRAM configured to load RISC load.\n")); + status = 1; + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print( + "qla1280_isp_firmware: **** Load RISC code ****\n\r"); +#endif + LEAVE("qla1280_isp_firmware"); + return(status); +} + +/* + * PCI configuration + * Setup device PCI configuration registers. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_pci_config(scsi_qla_host_t *ha) +{ + uint8_t status = 1; + uint32_t command; +#if MEMORY_MAPPED_IO + uint32_t page_offset, base; + uint32_t mmapbase; +#endif + config_reg_t *creg = 0; + uint16_t buf_wd; + + ENTER("qla1280_pci_config"); + + /* Get command register. */ + if (pci_read_config_word(ha->pdev,OFFSET(creg->command), &buf_wd) == PCIBIOS_SUCCESSFUL) + { + command = buf_wd; + /* + * Set Bus Master Enable, Memory Address Space Enable and + * reset any error bits. + */ + buf_wd &= ~0x7; +#if MEMORY_MAPPED_IO + DEBUG(printk("qla1280: MEMORY MAPPED IO is enabled.\n")); + buf_wd |= BIT_2 + BIT_1 + BIT_0; +#else + buf_wd |= BIT_2 + BIT_0; +#endif + if( pci_write_config_word(ha->pdev,OFFSET(creg->command), buf_wd) ) + { + printk(KERN_WARNING "qla1280: Could not write config word.\n"); + } + /* Get expansion ROM address. */ + if (pci_read_config_word(ha->pdev,OFFSET(creg->expansion_rom), &buf_wd) == PCIBIOS_SUCCESSFUL) + { + /* Reset expansion ROM address decode enable. */ + buf_wd &= ~BIT_0; + if (pci_write_config_word(ha->pdev,OFFSET(creg->expansion_rom), buf_wd) == PCIBIOS_SUCCESSFUL) + { +#if MEMORY_MAPPED_IO + /* Get memory mapped I/O address. */ + pci_read_config_dword(ha->pdev,OFFSET(cfgp->mem_base_addr), &mmapbase); + mmapbase &= PCI_BASE_ADDRESS_MEM_MASK; + + /* Find proper memory chunk for memory map I/O reg. */ + base = mmapbase & PAGE_MASK; + page_offset = mmapbase - base; + /* Get virtual address for I/O registers. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) + ha->mmpbase = ioremap_nocache(base, page_offset + 256); +#else + ha->mmpbase = vremap(base,page_offset + 256); +#endif + if( ha->mmpbase ) + { + ha->mmpbase += page_offset; + /* ha->iobase = ha->mmpbase; */ + status = 0; + } +#else /* MEMORY_MAPPED_IO */ + status = 0; +#endif /* MEMORY_MAPPED_IO */ + } + } + } + + LEAVE("qla1280_pci_config"); + return(status); +} + +/* + * Chip diagnostics + * Test chip for proper operation. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_chip_diag(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + uint16_t data; + uint32_t cnt; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + sprintf(debug_buff, "qla1280_chip_diag: testing device at 0x%p \n\r",®->id_l); + qla1280_print(debug_buff); +#endif + + /* Soft reset chip and wait for it to finish. */ + WRT_REG_WORD(®->ictrl, ISP_RESET); + data = qla1280_debounce_register(®->ictrl); + for (cnt = 6000000; cnt && data & ISP_RESET; cnt--) + { + SYS_DELAY(5); + data = RD_REG_WORD(®->ictrl); + } + if (cnt) + { + /* Reset register not cleared by chip reset. */ +#if defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_chip_diag: reset register cleared by chip reset\n\r"); +#endif + WRT_REG_WORD(®->cfg_1, 0); + + /* Reset RISC and disable BIOS which + allows RISC to execute out of RAM. */ + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); + data = qla1280_debounce_register(®->mailbox0); + for (cnt = 6000000; cnt && data == MBS_BUSY; cnt--) + { + SYS_DELAY(5); + data = RD_REG_WORD(®->mailbox0); + } + + if (cnt) + { + /* Check product ID of chip */ +#if defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_chip_diag: Checking product ID of chip\n\r"); +#endif + if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || + (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && + RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || + RD_REG_WORD(®->mailbox3) != PROD_ID_3 || + RD_REG_WORD(®->mailbox4) != PROD_ID_4) + { + printk(KERN_INFO "qla1280: Wrong product ID = 0x%x,0x%x,0x%x,0x%x\n", + RD_REG_WORD(®->mailbox1), + RD_REG_WORD(®->mailbox2), + RD_REG_WORD(®->mailbox3), + RD_REG_WORD(®->mailbox4) ); + status = 1; + } + else + { + DEBUG(printk("qla1280_chip_diag: Checking mailboxes of chip\n")); + /* Wrap Incoming Mailboxes Test. */ + mb[0] = MBC_MAILBOX_REGISTER_TEST; + mb[1] = 0xAAAA; + mb[2] = 0x5555; + mb[3] = 0xAA55; + mb[4] = 0x55AA; + mb[5] = 0xA5A5; + mb[6] = 0x5A5A; + mb[7] = 0x2525; + if (!(status = qla1280_mailbox_command(ha, + (BIT_7|BIT_6|BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0), + &mb[0]))) + { + if (mb[1] != 0xAAAA || mb[2] != 0x5555 || + mb[3] != 0xAA55 || mb[4] != 0x55AA) + status = 1; + if (mb[5] != 0xA5A5 || mb[6] != 0x5A5A || + mb[7] != 0x2525) + status = 1; + if( status == 1 ) + printk(KERN_INFO "qla1280: Failed mailbox check\n"); + } + } + } + else + status = 1; + } + else + status = 1; + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_chip_diag: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_chip_diag: exiting normally\n\r"); +#endif + return(status); +} + +/* + * Setup chip + * Load and start RISC firmware. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_setup_chip(scsi_qla_host_t *ha) +{ + uint8_t status = 0; + uint16_t risc_address; + uint16_t *risc_code_address; + long risc_code_size; + uint16_t mb[MAILBOX_REGISTER_COUNT]; +#ifdef QLA1280_UNUSED + int i; +#endif + uint16_t cnt; + int num; + uint8_t *tbuf, *sp; + u_long p_tbuf; + int i; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_setup_chip"); +#endif + + if( (tbuf = (uint8_t *)KMALLOC(8000) ) == NULL ) + { + printk("setup_chip: couldn't alloacte memory\n"); + return(1); + } + p_tbuf = VIRT_TO_BUS(tbuf); + /* Load RISC code. */ + /* + risc_address = ql12_risc_code_addr01; + risc_code_address = &ql12_risc_code01[0]; + risc_code_size = ql12_risc_code_length01; + */ + risc_address = *QLBoardTbl[ha->devnum].fwstart; + risc_code_address = QLBoardTbl[ha->devnum].fwcode; + risc_code_size = (long)(*QLBoardTbl[ha->devnum].fwlen & 0xffff); + + DEBUG(printk("qla1280: DMAing RISC code (%d) words.\n",(int)risc_code_size)); + DEBUG(sprintf(debug_buff,"qla1280_setup_chip: Loading RISC code size =(%ld).\n\r",risc_code_size);) + DEBUG(qla1280_print(debug_buff)); + num =0; + while (risc_code_size > 0 && !status) + { + cnt = 2000 >> 1; + + if ( cnt > risc_code_size ) + cnt = risc_code_size; + + DEBUG(sprintf(debug_buff,"qla1280_setup_chip: loading risc @ =(0x%p),%d,%d(0x%x).\n\r",risc_code_address,cnt,num,risc_address);) + DEBUG(qla1280_print(debug_buff)); + printk("qla1280_setup_chip: loading risc @ =code=(0x%p),cnt=%d,seg=%d,addr=0x%x\n\r",risc_code_address,cnt,num,risc_address); + BCOPY((caddr_t) risc_code_address,(caddr_t) ha->request_ring, (cnt <<1)); + mb[0] = MBC_LOAD_RAM; + /* mb[0] = MBC_LOAD_RAM_A64; */ + mb[1] = risc_address; + mb[4] = cnt; + mb[3] = (uint16_t) ha->request_dma & 0xffff; + mb[2] = (uint16_t) (ha->request_dma >> 16) & 0xffff; + mb[7] = (uint16_t) (MS_64BITS(ha->request_dma) & 0xffff); + mb[6] = (uint16_t) (MS_64BITS(ha->request_dma) >> 16) & 0xffff; + printk("qla1280_setup_chip: op=%d 0x%lx = 0x%4x,0x%4x,0x%4x,0x%4x\n",mb[0],ha->request_dma,mb[6],mb[7],mb[2],mb[3]); + if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0])) ) + { + printk("Failed to load partial segment of f/w\n"); + break; + } + /* dump it back */ + +#if 0 + mb[0] = MBC_DUMP_RAM_A64; + mb[1] = risc_address; + mb[4] = cnt; + mb[3] = (uint16_t) p_tbuf & 0xffff; + mb[2] = (uint16_t) (p_tbuf >> 16) & 0xffff; + mb[7] = (uint16_t) (p_tbuf >> 32) & 0xffff; + mb[6] = (uint16_t) (p_tbuf >> 48) & 0xffff; + + if( (status = qla1280_mailbox_command(ha, BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0])) ) + { + printk("Failed to dump partial segment of f/w\n"); + break; + } + sp = (uint8_t *)ha->request_ring; + for (i = 0; i < (cnt<< 1) ; i++) + { + if( tbuf[i] != sp[i] ) + { + printk("qla1280 : firmware compare error @ byte (0x%x)\n",i); + break; + } + } + +#endif + risc_address += cnt; + risc_code_size = risc_code_size - cnt; + risc_code_address = risc_code_address + cnt; + num++; + } +#ifdef QLA1280_UNUSED + DEBUG(ql_debug_print = 0;) + { + for (i = 0; i < ql12_risc_code_length01; i++) + { + mb[0] = 0x4; + mb[1] = ql12_risc_code_addr01 + i; + mb[2] = ql12_risc_code01[i]; + + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, + &mb[0]); + if (status) + { + printk("qla1280 : firmware load failure\n"); + break; + } + + mb[0] = 0x5; + mb[1] = ql12_risc_code_addr01 + i; + mb[2] = 0; + + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, + &mb[0]); + if (status) + { + printk("qla1280 : firmware dump failure\n"); + break; + } + if( mb[2] != ql12_risc_code01[i] ) + printk("qla1280 : firmware compare error @ (0x%x)\n",ql12_risc_code_addr01+i); + } + } + DEBUG(ql_debug_print = 1;) +#endif + + /* Verify checksum of loaded RISC code. */ + if (!status) + { + DEBUG(printk("qla1280_setup_chip: Verifying checksum of loaded RISC code.\n");) + mb[0] = MBC_VERIFY_CHECKSUM; + /* mb[1] = ql12_risc_code_addr01; */ + mb[1] = *QLBoardTbl[ha->devnum].fwstart; + + if (!(status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]))) + { + /* Start firmware execution. */ + DEBUG(qla1280_print("qla1280_setup_chip: start firmware running.\n\r");) + mb[0] = MBC_EXECUTE_FIRMWARE; + /* mb[1] = ql12_risc_code_addr01; */ + mb[1] = *QLBoardTbl[ha->devnum].fwstart; + qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + } + else + printk("qla1280_setup_chip: Failed checksum.\n"); + } + + KMFREE(tbuf,8000); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_setup_chip: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_setup_chip"); +#endif + return(status); +} + +/* + * Initialize rings + * + * Input: + * ha = adapter block pointer. + * ha->request_ring = request ring virtual address + * ha->response_ring = response ring virtual address + * ha->request_dma = request ring physical address + * ha->response_dma = response ring physical address + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_init_rings(scsi_qla_host_t *ha) +{ + uint8_t status = 0; + uint16_t cnt; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_init_rings"); +#endif + /* Clear outstanding commands array. */ + for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) + ha->outstanding_cmds[cnt] = 0; + + /* Initialize request queue. */ + ha->request_ring_ptr = ha->request_ring; + ha->req_ring_index = 0; + ha->req_q_cnt = REQUEST_ENTRY_CNT; + /* mb[0] = MBC_INIT_REQUEST_QUEUE; */ + mb[0] = MBC_INIT_REQUEST_QUEUE_A64; + mb[1] = REQUEST_ENTRY_CNT; + mb[3] = (uint16_t)LS_64BITS(ha->request_dma); + mb[2] = (uint16_t)( LS_64BITS(ha->request_dma) >> 16); + mb[4] = 0; + mb[7] = (uint16_t)MS_64BITS(ha->request_dma); + mb[6] = (uint16_t)( MS_64BITS(ha->request_dma) >> 16); + if (!(status = qla1280_mailbox_command(ha, + BIT_7|BIT_6|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]))) + { + /* Initialize response queue. */ + ha->response_ring_ptr = ha->response_ring; + ha->rsp_ring_index = 0; + /* mb[0] = MBC_INIT_RESPONSE_QUEUE; */ + mb[0] = MBC_INIT_RESPONSE_QUEUE_A64; + mb[1] = RESPONSE_ENTRY_CNT; + mb[3] = (uint16_t)LS_64BITS(ha->response_dma); + mb[2] = (uint16_t)(LS_64BITS(ha->response_dma) >> 16); + mb[5] = 0; + mb[7] = (uint16_t)MS_64BITS(ha->response_dma); + mb[6] = (uint16_t)(MS_64BITS(ha->response_dma) >> 16); + status = qla1280_mailbox_command(ha, + BIT_7|BIT_6|BIT_5|BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_init_rings: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_init_rings"); +#endif + return(status); +} + +/* + * NVRAM configuration. + * + * Input: + * ha = adapter block pointer. + * ha->request_ring = request ring virtual address + * + * Output: + * host adapters parameters in host adapter block + * + * Returns: + * 0 = success. + */ +STATIC uint8_t +qla1280_nvram_config(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + nvram_t *nv = (nvram_t *)ha->response_ring; + uint8_t status = 0; + uint32_t b, t, l; + uint16_t *wptr; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint8_t cnt; + uint8_t chksum; + uint32_t nvsize; + +#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4) + uint8_t saved_print_status = ql_debug_print; +#endif + ENTER("qla1280_nvram_config"); +#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4) + ql_debug_print = FALSE; +#endif + + /* Verify valid NVRAM checksum. */ +#if USE_NVRAM_DEFAULTS + chksum = 1; +#else + wptr = (uint16_t *)ha->response_ring; + chksum = 0; + if( ha->device_id == QLA12160_DEVICE_ID || + ha->device_id == QLA10160_DEVICE_ID ) + nvsize = sizeof(nvram160_t)/2; + else + nvsize = sizeof(nvram_t)/2; + for( cnt = 0; cnt < nvsize; cnt++ ) + { + *wptr = qla1280_get_nvram_word(ha, cnt); + chksum += (uint8_t)*wptr; + chksum += (uint8_t)(*wptr >> 8); + wptr++; + } +#endif + + + /* Bad NVRAM data, set defaults parameters. */ + if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || + nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) + { +#if USE_NVRAM_DEFAULTS + DEBUG(printk("Using defaults for NVRAM\n")); +#else + DEBUG(printk("Using defaults for NVRAM: \n")); + DEBUG(printk("checksum=0x%x, Id=%c, version=0x%x\n",chksum,nv->id[0],nv->version)); +#if defined(QL_DEBUG_LEVEL_3) + /* ql_debug_print = 1; + qla1280_dump_buffer((caddr_t)ha->response_ring, REQUEST_ENTRY_SIZE); + ql_debug_print = 0; */ +#endif + wptr = (uint16_t *)ha->response_ring; + for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++) + *wptr++ = 0; +#endif + + + /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ + nv->firmware_feature.w = BIT_0; + nv->termination.f.scsi_bus_0_control = 3; + nv->termination.f.scsi_bus_1_control = 3; + nv->termination.f.auto_term_support = 1; + + for (b = 0; b < MAX_BUSES; b++) + { + nv->bus[b].config_1.initiator_id = 7; + nv->bus[b].bus_reset_delay = 5; + nv->bus[b].config_2.async_data_setup_time = 9; + nv->bus[b].config_2.req_ack_active_negation = 1; + nv->bus[b].config_2.data_line_active_negation = 1; + nv->bus[b].selection_timeout = 250; + nv->bus[b].max_queue_depth = 256; + + for (t = 0; t < MAX_TARGETS; t++) + { + nv->bus[b].target[t].parameter.f.auto_request_sense = 1; + nv->bus[b].target[t].parameter.f.disconnect_allowed = 1; + nv->bus[b].target[t].parameter.f.tag_queuing = 1; + nv->bus[b].target[t].flags.device_enable = 1; + } + } + +#if USE_NVRAM_DEFAULTS + status = 0; +#else + status = 1; +#endif + } + else + { + /* Always force AUTO sense for LINUX SCSI */ + for (b = 0; b < MAX_BUSES; b++) + for (t = 0; t < MAX_TARGETS; t++) + { + nv->bus[b].target[t].parameter.f.auto_request_sense = 1; + } + } +#if DEBUG_PRINT_NVRAM + ql_debug_print = 1; + sprintf(debug_buff,"qla1280 : initiator scsi id bus[0]=%d\n\r", + nv->bus[0].config_1.initiator_id); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : initiator scsi id bus[1]=%d\n\r", + nv->bus[1].config_1.initiator_id); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : bus reset delay[0]=%d\n\r", + nv->bus[0].bus_reset_delay); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : bus reset delay[1]=%d\n\r", + nv->bus[1].bus_reset_delay); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : retry count[0]=%d\n\r", + nv->bus[0].retry_count); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : retry delay[0]=%d\n\r", + nv->bus[0].retry_delay); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : retry count[1]=%d\n\r", + nv->bus[1].retry_count); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : retry delay[1]=%d\n\r", + nv->bus[1].retry_delay); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : async data setup time[0]=%d\n\r", + nv->bus[0].config_2.async_data_setup_time); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : async data setup time[1]=%d\n\r", + nv->bus[1].config_2.async_data_setup_time); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : req/ack active negation[0]=%d\n\r", + nv->bus[0].config_2.req_ack_active_negation); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : req/ack active negation[1]=%d\n\r", + nv->bus[1].config_2.req_ack_active_negation); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : data line active negation[0]=%d\n\r", + nv->bus[0].config_2.data_line_active_negation); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : data line active negation[1]=%d\n\r", + nv->bus[1].config_2.data_line_active_negation); + qla1280_print(debug_buff); + + + sprintf(debug_buff,"qla1280 : disable loading risc code=%d\n\r", + nv->cntr_flags_1.disable_loading_risc_code); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : enable 64bit addressing=%d\n\r", + nv->cntr_flags_1.enable_64bit_addressing); + qla1280_print(debug_buff); + + sprintf(debug_buff,"qla1280 : selection timeout limit[0]=%d\n\r", + nv->bus[0].selection_timeout); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : selection timeout limit[1]=%d\n\r", + nv->bus[1].selection_timeout); + + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : max queue depth[0]=%d\n\r", + nv->bus[0].max_queue_depth); + qla1280_print(debug_buff); + sprintf(debug_buff,"qla1280 : max queue depth[1]=%d\n\r", + nv->bus[1].max_queue_depth); + qla1280_print(debug_buff); +#endif + + DEBUG(ql_debug_print = 0;) + + /* Disable RISC load of firmware. */ + ha->flags.disable_risc_code_load = + nv->cntr_flags_1.disable_loading_risc_code; + /* Enable 64bit addressing. */ + ha->flags.enable_64bit_addressing = + nv->cntr_flags_1.enable_64bit_addressing; + + /* Set ISP hardware DMA burst */ + mb[0] = nv->isp_config.c; + WRT_REG_WORD(®->cfg_1, mb[0]); + + /* Set SCSI termination. */ + WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); + mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); + WRT_REG_WORD(®->gpio_data, mb[0]); + + /* ISP parameter word. */ + mb[0] = MBC_SET_SYSTEM_PARAMETER; + mb[1] = nv->isp_parameter; + status |= qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + + /* Firmware feature word. */ + mb[0] = MBC_SET_FIRMWARE_FEATURES; + mb[1] = nv->firmware_feature.w & (BIT_1|BIT_0); + status |= qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + + /* Retry count and delay. */ + mb[0] = MBC_SET_RETRY_COUNT; + mb[1] = nv->bus[0].retry_count; + mb[2] = nv->bus[0].retry_delay; + mb[6] = nv->bus[1].retry_count; + mb[7] = nv->bus[1].retry_delay; + status |= qla1280_mailbox_command(ha, BIT_7|BIT_6|BIT_2|BIT_1|BIT_0, &mb[0]); + + /* ASYNC data setup time. */ + mb[0] = MBC_SET_ASYNC_DATA_SETUP; + mb[1] = nv->bus[0].config_2.async_data_setup_time; + mb[2] = nv->bus[1].config_2.async_data_setup_time; + status |= qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + /* Active negation states. */ + mb[0] = MBC_SET_ACTIVE_NEGATION; + mb[1] = 0; + if (nv->bus[0].config_2.req_ack_active_negation) + mb[1] |= BIT_5; + if (nv->bus[0].config_2.data_line_active_negation) + mb[1] |= BIT_4; + mb[2] = 0; + if (nv->bus[1].config_2.req_ack_active_negation) + mb[2] |= BIT_5; + if (nv->bus[1].config_2.data_line_active_negation) + mb[2] |= BIT_4; + status |= qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + /* Selection timeout. */ + mb[0] = MBC_SET_SELECTION_TIMEOUT; + mb[1] = nv->bus[0].selection_timeout; + mb[2] = nv->bus[1].selection_timeout; + status |= qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + for (b = 0; b < ha->ports; b++) + { + /* SCSI Reset Disable. */ + ha->bus_settings[b].disable_scsi_reset = nv->bus[b].config_1.scsi_reset_disable; + + /* Initiator ID. */ + ha->bus_settings[b].id = nv->bus[b].config_1.initiator_id; + mb[0] = MBC_SET_INITIATOR_ID; + mb[1] = b ? ha->bus_settings[b].id | BIT_7 : ha->bus_settings[b].id; + status |= qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + + /* Reset Delay. */ + ha->bus_settings[b].bus_reset_delay = nv->bus[b].bus_reset_delay; + + /* Command queue depth per device. */ + ha->bus_settings[b].hiwat = nv->bus[b].max_queue_depth - 1; + + /* Set target parameters. */ + for (t = 0; t < MAX_TARGETS; t++) + { + if( ha->device_id == QLA12160_DEVICE_ID || + ha->device_id == QLA10160_DEVICE_ID ) + { + status = qla12160_set_target_parameters(ha,b,t,0,(nvram160_t *)nv); + } + else + { + /* Set Target Parameters. */ + mb[0] = MBC_SET_TARGET_PARAMETERS; + mb[1] = (uint16_t)(b ? t | BIT_7 :t); + mb[1] <<= 8; + mb[2] = nv->bus[b].target[t].parameter.c << 8; + mb[2] |= TP_AUTO_REQUEST_SENSE; + mb[2] &= ~TP_STOP_QUEUE; + mb[3] = nv->bus[b].target[t].flags.sync_offset << 8; + mb[3] |= nv->bus[b].target[t].sync_period; + status |= qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + } + + /* Save Tag queuing enable flag. */ + mb[0] = BIT_0 << t; + if (nv->bus[b].target[t].parameter.f.tag_queuing) + ha->bus_settings[b].qtag_enables |= mb[0]; + + /* Save Device enable flag. */ + if (nv->bus[b].target[t].flags.device_enable) + ha->bus_settings[b].device_enables |= mb[0]; + + /* Save LUN disable flag. */ + if (nv->bus[b].target[t].flags.lun_disable) + ha->bus_settings[b].lun_disables |= mb[0]; + + /* Set Device Queue Parameters. */ + for (l = 0; l < MAX_LUNS; l++) + { + mb[0] = MBC_SET_DEVICE_QUEUE; + mb[1] = (uint16_t)(b ? t | BIT_7 :t); + mb[1] = mb[1] << 8 | l; + mb[2] = nv->bus[b].max_queue_depth; + mb[3] = nv->bus[b].target[t].execution_throttle; + status |= qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, + &mb[0]); + } + } + } + DEBUG(ql_debug_print = 0;) + +#if defined(QL_DEBUG_ROUTINES) && !defined(QL_DEBUG_LEVEL_4) + ql_debug_print = saved_print_status; +#endif + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + DEBUG(if (status)) + DEBUG(qla1280_print("qla1280_nvram_config: **** FAILED ****\n\r");) +#endif + LEAVE("qla1280_nvram_config"); + return(status); +} + +/* + * Get NVRAM data word + * Calculates word position in NVRAM and calls request routine to + * get the word from NVRAM. + * + * Input: + * ha = adapter block pointer. + * address = NVRAM word address. + * + * Returns: + * data word. + */ +STATIC uint16_t +qla1280_get_nvram_word(scsi_qla_host_t *ha, uint32_t address) +{ + uint32_t nv_cmd; + uint16_t data; + +#ifdef QL_DEBUG_ROUTINES + uint8_t saved_print_status = ql_debug_print; +#endif +#ifdef QL_DEBUG_LEVEL_4 + ENTER("qla1280_get_nvram_word"); +#endif + + nv_cmd = address << 16; + nv_cmd |= NV_READ_OP; + +#ifdef QL_DEBUG_ROUTINES + ql_debug_print = FALSE; +#endif + data = qla1280_nvram_request(ha, nv_cmd); +#ifdef QL_DEBUG_ROUTINES + ql_debug_print = saved_print_status; +#endif + +#ifdef QL_DEBUG_LEVEL_4 + qla1280_print("qla1280_get_nvram_word: exiting normally NVRAM data = "); + qla1280_output_number((uint32_t)data, 16); + qla1280_print("\n\r"); +#endif + return(data); +} + +/* + * NVRAM request + * Sends read command to NVRAM and gets data from NVRAM. + * + * Input: + * ha = adapter block pointer. + * nv_cmd = Bit 26 = start bit + * Bit 25, 24 = opcode + * Bit 23-16 = address + * Bit 15-0 = write data + * + * Returns: + * data word. + */ +STATIC uint16_t +qla1280_nvram_request(scsi_qla_host_t *ha, uint32_t nv_cmd) +{ + uint8_t cnt; + device_reg_t *reg = ha->iobase; + uint16_t data = 0; + uint16_t reg_data; + + /* Send command to NVRAM. */ + + nv_cmd <<= 5; + for (cnt = 0; cnt < 11; cnt++) + { + if (nv_cmd & BIT_31) + qla1280_nv_write(ha, NV_DATA_OUT); + else + qla1280_nv_write(ha, 0); + nv_cmd <<= 1; + } + + /* Read data from NVRAM. */ + + for (cnt = 0; cnt < 16; cnt++) + { + WRT_REG_WORD(®->nvram, NV_SELECT+NV_CLOCK); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); + data <<= 1; + reg_data = RD_REG_WORD(®->nvram); + if (reg_data & NV_DATA_IN) + data |= BIT_0; + WRT_REG_WORD(®->nvram, NV_SELECT); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); + } + + /* Deselect chip. */ + + WRT_REG_WORD(®->nvram, NV_DESELECT); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); + + return(data); +} + +STATIC void +qla1280_nv_write(scsi_qla_host_t *ha, uint16_t data) +{ + device_reg_t *reg = ha->iobase; + + WRT_REG_WORD(®->nvram, data | NV_SELECT); + NVRAM_DELAY(); + /* qla1280_nv_delay(ha); */ + WRT_REG_WORD(®->nvram, data | NV_SELECT | NV_CLOCK); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); + WRT_REG_WORD(®->nvram, data | NV_SELECT); + /* qla1280_nv_delay(ha); */ + NVRAM_DELAY(); +} + +STATIC void +qla1280_nv_delay(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + int cnt = NV_DELAY_COUNT; + uint16_t data = 0; + + while (cnt--) + data |= RD_REG_WORD(®->nvram); +} + +/* + * Mailbox Command + * Issue mailbox command and waits for completion. + * + * Input: + * ha = adapter block pointer. + * mr = mailbox registers to load. + * mb = data pointer for mailbox registers. + * + * Output: + * mb[MAILBOX_REGISTER_COUNT] = returned mailbox data. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_mailbox_command(scsi_qla_host_t *ha, uint8_t mr, uint16_t *mb) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + uint32_t cnt; + uint16_t *optr, *iptr; + uint16_t data; + srb_t *done_q_first = 0; + srb_t *done_q_last = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_mailbox_command"); +#endif + + /* Acquire interrupt specific lock */ + QLA1280_INTR_LOCK(ha); + DRIVER_LOCK + ha->flags.mbox_busy = TRUE; + + /* Load mailbox registers. */ + optr = (uint16_t *)®->mailbox0; + iptr = mb; + for (cnt = 0; cnt < MAILBOX_REGISTER_COUNT; cnt++) + { + if (mr & BIT_0) + { + WRT_REG_WORD(optr, (*iptr)); + } + + mr >>= 1; + optr++; + iptr++; + } + /* Issue set host interrupt command. */ + ha->flags.mbox_int = FALSE; + WRT_REG_WORD(®->host_cmd, HC_SET_HOST_INT); + data = qla1280_debounce_register(®->istatus); + + /* Wait for 30 seconds for command to finish. */ + for (cnt = 30000000; cnt > 0 && !ha->flags.mbox_int; cnt--) + { + /* Check for pending interrupts. */ + if (data & RISC_INT) + { + qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + } + SYS_DELAY(1); + data = RD_REG_WORD(®->istatus); + } + + /* Check for mailbox command timeout. */ + if ( !cnt ) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_mailbox_command: **** Command Timeout, mailbox0 = "); + qla1280_output_number((uint32_t)mb[0], 16); + qla1280_print(" ****\n\r"); +#endif + ha->flags.isp_abort_needed = TRUE; + status = 1; + } + else if (ha->mailbox_out[0] != MBS_CMD_CMP) + status = 1; + + /* Load return mailbox registers. */ + optr = mb; + iptr = (uint16_t *)&ha->mailbox_out[0]; + mr = MAILBOX_REGISTER_COUNT; + while (mr--) + *optr++ = *iptr++; + + /* Go check for any response interrupts pending. */ + ha->flags.mbox_busy = FALSE; + qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + + /* Release interrupt specific lock */ + QLA1280_INTR_UNLOCK(ha); + DRIVER_UNLOCK + + if (ha->flags.isp_abort_needed) + qla1280_abort_isp(ha); + + if (ha->flags.reset_marker) + qla1280_rst_aen(ha); + + if (done_q_first) + qla1280_done(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + { + qla1280_print("qla1280_mailbox_command: **** FAILED, mailbox0 = "); + qla1280_output_number((uint32_t)mb[0], 16); + qla1280_print(" ****\n\r"); + } +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_mailbox_command"); +#endif + return(status); +} + +/* + * qla1280_poll + * Polls ISP for interrupts. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_poll(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + uint16_t data; + srb_t *done_q_first = 0; + srb_t *done_q_last = 0; + +#ifdef QL_DEBUG_LEVEL_3 + /* ENTER("qla1280_poll"); */ +#endif + + /* Acquire interrupt specific lock */ + QLA1280_INTR_LOCK(ha); + + /* Check for pending interrupts. */ + data = RD_REG_WORD(®->istatus); + if (data & RISC_INT) + qla1280_isr(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + + /* Release interrupt specific lock */ + QLA1280_INTR_UNLOCK(ha); + + if (!ha->flags.mbox_busy) + { + if (ha->flags.isp_abort_needed) + qla1280_abort_isp(ha); + if (ha->flags.reset_marker) + qla1280_rst_aen(ha); + } + + if (done_q_first) + qla1280_done(ha, (srb_t **)&done_q_first, (srb_t **)&done_q_last); + +#ifdef QL_DEBUG_LEVEL_3 + /* LEAVE("qla1280_poll"); */ +#endif +} + +/* + * qla1280_bus_reset + * Issue SCSI bus reset. + * + * Input: + * ha = adapter block pointer. + * b = SCSI bus number. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_bus_reset(scsi_qla_host_t *ha, uint8_t b) +{ + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_bus_reset: entered\n\r"); +#endif + if( qla1280_verbose ) + { + printk("scsi(%d): Resetting SCSI BUS (%d)\n",(int)ha->host_no,b); + } + + mb[0] = MBC_BUS_RESET; + mb[1] = ha->bus_settings[b].bus_reset_delay; + mb[2] = (uint16_t)b; + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + if (status) + { + if (ha->bus_settings[b].failed_reset_count > 2) /* dg - 03/13/99 */ + ha->bus_settings[b].scsi_bus_dead = TRUE; + ha->bus_settings[b].failed_reset_count++; + } + else + { + QLA1280_DELAY(4); + ha->bus_settings[b].scsi_bus_dead = FALSE; /* dg - 03/13/99 */ + ha->bus_settings[b].failed_reset_count = 0; + /* Issue marker command. */ + qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL); + } +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_bus_reset: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_bus_reset: exiting normally\n\r"); +#endif + return(status); +} + +/* + * qla1280_device_reset + * Issue bus device reset message to the target. + * + * Input: + * ha = adapter block pointer. + * b = SCSI BUS number. + * t = SCSI ID. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_device_reset(scsi_qla_host_t *ha, uint8_t b, uint32_t t) +{ + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_device_reset"); +#endif + + mb[0] = MBC_ABORT_TARGET; + mb[1] = (b ? (t | BIT_7) : t) << 8; + mb[2] = 1; + status = qla1280_mailbox_command(ha, BIT_2|BIT_1|BIT_0, &mb[0]); + + /* Issue marker command. */ + qla1280_marker(ha, b, t, 0, MK_SYNC_ID); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_device_reset: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_device_reset"); +#endif + return(status); +} + +/* + * qla1280_abort_device + * Issue an abort message to the device + * + * Input: + * ha = adapter block pointer. + * b = SCSI BUS. + * t = SCSI ID. + * l = SCSI LUN. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_abort_device(scsi_qla_host_t *ha, uint8_t b, uint32_t t, uint32_t l) +{ + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_abort_device"); +#endif + + mb[0] = MBC_ABORT_DEVICE; + mb[1] = (b ? t | BIT_7 : t) << 8 | l; + status = qla1280_mailbox_command(ha, BIT_1|BIT_0, &mb[0]); + + /* Issue marker command. */ + qla1280_marker(ha, b, t, l, MK_SYNC_ID_LUN); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_abort_device: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_abort_device"); +#endif + return(status); +} + +/* + * qla1280_abort_command + * Abort command aborts a specified IOCB. + * + * Input: + * ha = adapter block pointer. + * sp = SB structure pointer. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_abort_command(scsi_qla_host_t *ha, srb_t *sp) +{ + uint8_t status; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + uint32_t b, t, l; + uint32_t handle; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_abort_command"); +#endif + + /* Locate handle number. */ + for (handle = 0; handle < MAX_OUTSTANDING_COMMANDS; handle++) + if (ha->outstanding_cmds[handle] == sp) + break; + + b = SCSI_BUS_32(sp->cmd); + t = SCSI_TCN_32(sp->cmd); + l = SCSI_LUN_32(sp->cmd); + + mb[0] = MBC_ABORT_COMMAND; + mb[1] = (b ? t | BIT_7 : t) << 8 | l; + mb[2] = handle >> 16; + mb[3] = (uint16_t)handle; + status = qla1280_mailbox_command(ha, BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_abort_command: **** FAILED ****\n\r"); +#endif + sp->flags |= SRB_ABORT_PENDING; + + LEAVE("qla1280_abort_command"); + return(status); +} + +/* + * qla1280_reset_adapter + * Reset adapter. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_reset_adapter(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_reset_adapter"); +#endif + + /* Disable ISP chip */ + ha->flags.online = FALSE; + WRT_REG_WORD(®->ictrl, ISP_RESET); + WRT_REG_WORD(®->host_cmd, HC_RESET_RISC); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + WRT_REG_WORD(®->host_cmd, HC_DISABLE_BIOS); + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_reset_adapter"); +#endif +} + +/* + * Issue marker command. + * Function issues marker IOCB. + * + * Input: + * ha = adapter block pointer. + * b = SCSI BUS number + * t = SCSI ID + * l = SCSI LUN + * type = marker modifier + */ +STATIC void +qla1280_marker(scsi_qla_host_t *ha, uint8_t b, uint32_t t, uint32_t l, uint8_t type) +{ + mrk_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_marker"); +#endif + + /* Get request packet. */ + if ( (pkt = (mrk_entry_t *)qla1280_req_pkt(ha)) ) + { + pkt->entry_type = MARKER_TYPE; + pkt->lun = (uint8_t)l; + pkt->target = (uint8_t)(b ? (t | BIT_7) : t); + pkt->modifier = type; + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_marker"); +#endif +} + +#if QLA1280_64BIT_SUPPORT +/* + * qla1280_64bit_start_scsi + * The start SCSI is responsible for building request packets on + * request ring and modifying ISP input pointer. + * + * Input: + * ha = adapter block pointer. + * sp = SB structure pointer. + * + * Returns: + * 0 = success, was able to issue command. + */ +STATIC uint8_t +qla1280_64bit_start_scsi(scsi_qla_host_t *ha, srb_t *sp) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + Scsi_Cmnd *cmd = sp->cmd; + uint32_t cnt; + cmd_a64_entry_t *pkt; + uint16_t req_cnt; + uint16_t seg_cnt; + struct scatterlist *sg = (struct scatterlist *) NULL; + uint32_t *dword_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_64bit_start_scsi:"); +#endif + + if( qla1280_check_for_dead_scsi_bus(ha, sp) ) + { + return(0); + } + + /* Calculate number of entries and segments required. */ + seg_cnt = 0; + req_cnt = 1; + if (cmd->use_sg) + { + seg_cnt = cmd->use_sg; + sg = (struct scatterlist *) cmd->request_buffer; + + if (seg_cnt > 2) + { + req_cnt += (uint16_t)(seg_cnt - 2) / 5; + if ((uint16_t)(seg_cnt - 2) % 5) + req_cnt++; + } + } + else if (cmd->request_bufflen) /* If data transfer. */ + { + DEBUG(printk("Single data transfer (0x%x)\n",cmd->request_bufflen)); + seg_cnt = 1; + } + + /* Acquire ring specific lock */ + QLA1280_RING_LOCK(ha); + + if ((uint16_t)(req_cnt + 2) >= ha->req_q_cnt) + { + /* Calculate number of free request entries. */ + cnt = RD_REG_WORD(®->mailbox4); + if (ha->req_ring_index < cnt) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); + } + + /* If room for request in request ring. */ + if ((uint16_t)(req_cnt + 2) < ha->req_q_cnt) + { + /* Check for room in outstanding command list. */ + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && + ha->outstanding_cmds[cnt] != 0; cnt++) + ; + + if (cnt < MAX_OUTSTANDING_COMMANDS) + { + ha->outstanding_cmds[cnt] = sp; + ha->req_q_cnt -= req_cnt; + CMD_HANDLE(sp->cmd) = (unsigned char *) (u_long) cnt; + + /* + * Build command packet. + */ + pkt = (cmd_a64_entry_t *)ha->request_ring_ptr; + + pkt->entry_type = COMMAND_A64_TYPE; + pkt->entry_count = (uint8_t)req_cnt; + pkt->sys_define = (uint8_t)ha->req_ring_index; + pkt->handle = (uint32_t)cnt; + + /* Zero out remaining portion of packet. */ + dword_ptr = (uint32_t *)pkt + 2; + for (cnt = 2; cnt < REQUEST_ENTRY_SIZE/4; cnt++) + *dword_ptr++ = 0; + + /* Set ISP command timeout. */ + pkt->timeout = (uint16_t)30; + + /* Set device target ID and LUN */ + pkt->lun = SCSI_LUN_32(cmd); + pkt->target = SCSI_BUS_32(cmd) ? + (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd); + + /* Enable simple tag queuing if device supports it. */ + if (cmd->device->tagged_queue ) + pkt->control_flags |= BIT_3; + + /* Load SCSI command packet. */ + pkt->cdb_len = (uint16_t)CMD_CDBLEN(cmd); + BCOPY(&(CMD_CDBP(cmd)), pkt->scsi_cdb, pkt->cdb_len); + DEBUG(printk("Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0])); + + /* + * Load data segments. + */ + if (seg_cnt) /* If data transfer. */ + { + /* Set transfer direction. */ + if ( (cmd->data_cmnd[0] == WRITE_6) ) + pkt->control_flags |= BIT_6; + else + pkt->control_flags |= (BIT_5|BIT_6); + + sp->dir = pkt->control_flags & (BIT_5|BIT_6); + + /* Set total data segment count. */ + pkt->dseg_count = seg_cnt; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *)&pkt->dseg_0_address; + + if (cmd->use_sg) /* If scatter gather */ + { + /* Load command entry data segments. */ + for (cnt = 0; cnt < 2 && seg_cnt; cnt++, seg_cnt--) + { + DEBUG(sprintf(debug_buff,"SG Segment ap=0x%p, len=0x%x\n\r",sg->address,sg->length)); + DEBUG(qla1280_print(debug_buff)); + *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(sg->address)); + *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(sg->address)); + *dword_ptr++ = sg->length; + sg++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_64bit_start_scsi: Scatter/gather command packet data - "); + qla1280_print("b "); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla1280_print(" t "); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print(" d "); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + /* + * Build continuation packets. + */ + while (seg_cnt > 0) + { + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) + { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } + else + ha->request_ring_ptr++; + + pkt = (cmd_a64_entry_t *)ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for (cnt = 0;cnt < REQUEST_ENTRY_SIZE/4; cnt++) + *dword_ptr++ = 0; + + /* Load packet defaults. */ + ((cont_a64_entry_t *)pkt)->entry_type = + CONTINUE_A64_TYPE; + ((cont_a64_entry_t *)pkt)->entry_count = 1; + ((cont_a64_entry_t *)pkt)->sys_define = (uint8_t) + ha->req_ring_index; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *) + &((cont_a64_entry_t *)pkt)->dseg_0_address; + + /* Load continuation entry data segments. */ + for (cnt = 0; cnt < 5 && seg_cnt; cnt++, seg_cnt--) + { + *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(sg->address)); + *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(sg->address)); + *dword_ptr++ = sg->length; + sg++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_64bit_start_scsi: continuation packet data - c"); + qla1280_print(" b "); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + + qla1280_print(" t "); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print(" d "); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } + else /* No scatter gather data transfer */ + { + *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_LOW(cmd->request_buffer)); + *dword_ptr++ = cpu_to_le32(VIRT_TO_BUS_HIGH(cmd->request_buffer)); + *dword_ptr = (uint32_t) cmd->request_bufflen; +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_64bit_start_scsi: No scatter/gather command packet data - c"); + qla1280_print(" b "); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla1280_print(" t "); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print(" d "); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } +#ifdef QL_DEBUG_LEVEL_5 + else /* No data transfer */ + { + *dword_ptr++ = (uint32_t) 0; + *dword_ptr++ = (uint32_t) 0; + *dword_ptr = (uint32_t) 0; + qla1280_print( + "qla1280_64bit_start_scsi: No data, command packet data - c"); + qla1280_print(" b "); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla1280_print(" t "); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print(" d "); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); + } +#endif + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) + { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } + else + ha->request_ring_ptr++; + + /* Set chip new ring index. */ + WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + } + else + { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_64bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r"); + qla1280_print(" req_q_cnt="); + qla1280_output_number((uint32_t)ha->req_q_cnt, 16); +#endif + } + } + else + { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_64bit_start_scsi: in-ptr="); + qla1280_output_number((uint32_t)ha->req_ring_index, 16); + qla1280_print(" req_q_cnt="); + qla1280_output_number((uint32_t)ha->req_q_cnt, 16); + qla1280_print(" req_cnt="); + qla1280_output_number((uint32_t)req_cnt, 16); + qla1280_print("\n\r"); +#endif + } + + /* Release ring specific lock */ + QLA1280_RING_UNLOCK(ha); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (status) + qla1280_print("qla1280_64bit_start_scsi: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_64bit_start_scsi: exiting normally\n\r"); +#endif + return(status); +} +#endif /* QLA1280_64BIT_SUPPORT */ + +/* + * qla1280_32bit_start_scsi + * The start SCSI is responsible for building request packets on + * request ring and modifying ISP input pointer. + * + * The Qlogic firmware interface allows every queue slot to have a SCSI + * command and up to 4 scatter/gather (SG) entries. If we need more + * than 4 SG entries, then continuation entries are used that can + * hold another 7 entries each. The start routine determines if there + * is eought empty slots then build the combination of requests to + * fulfill the OS request. + * + * Input: + * ha = adapter block pointer. + * sp = SCSI Request Block structure pointer. + * + * Returns: + * 0 = success, was able to issue command. + */ +STATIC uint8_t +qla1280_32bit_start_scsi(scsi_qla_host_t *ha, srb_t *sp) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + Scsi_Cmnd *cmd = sp->cmd; + uint32_t cnt; + cmd_entry_t *pkt; + uint16_t req_cnt; + uint16_t seg_cnt; + struct scatterlist *sg = (struct scatterlist *) NULL; + uint8_t *data_ptr; + uint32_t *dword_ptr; + + ENTER("qla1280_32bit_start_scsi"); + + + if( qla1280_check_for_dead_scsi_bus(ha, sp) ) + { + return(0); + } + + /* Calculate number of entries and segments required. */ + req_cnt = 1; + if (cmd->use_sg) + { + /* + * We must build an SG list in adapter format, as the kernel's SG list + * cannot be used directly because of data field size (__alpha__) + * differences and the kernel SG list uses virtual addresses where + * we need physical addresses. + */ + seg_cnt = cmd->use_sg; + sg = (struct scatterlist *) cmd->request_buffer; + /* + * if greater than four sg entries then we need to allocate + * continuation entries + */ + if (seg_cnt > 4) + { + req_cnt += (uint16_t)(seg_cnt - 4) / 7; + if ((uint16_t)(seg_cnt - 4) % 7) + req_cnt++; + } + DEBUG(sprintf(debug_buff,"S/G for data transfer -num segs(%d), req blk cnt(%d)\n\r",seg_cnt,req_cnt)); + DEBUG(qla1280_print(debug_buff)); + } + else if (cmd->request_bufflen) /* If data transfer. */ + { + DEBUG(printk("Single data transfer (0x%x)\n",cmd->request_bufflen)); + seg_cnt = 1; + } + else + { + DEBUG(printk("No data transfer \n")); + seg_cnt = 0; + } + + /* Acquire ring specific lock */ + QLA1280_RING_LOCK(ha); + + if ((uint16_t)(req_cnt + 2) >= ha->req_q_cnt) + { + /* Calculate number of free request entries. */ + cnt = RD_REG_WORD(®->mailbox4); + if (ha->req_ring_index < cnt) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); + } + + DEBUG(sprintf(debug_buff,"Number of free entries = (%d)\n\r",ha->req_q_cnt)); + DEBUG(qla1280_print(debug_buff)); + /* If room for request in request ring. */ + if ((uint16_t)(req_cnt + 2) < ha->req_q_cnt) + { + /* Check for empty slot in outstanding command list. */ + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS && + (ha->outstanding_cmds[cnt] != 0); cnt++) + ; + + if (cnt < MAX_OUTSTANDING_COMMANDS) + { + CMD_HANDLE(sp->cmd) = (unsigned char *)(unsigned long)cnt; + ha->outstanding_cmds[cnt] = sp; + ha->req_q_cnt -= req_cnt; + + /* + * Build command packet. + */ + pkt = (cmd_entry_t *)ha->request_ring_ptr; + + pkt->entry_type = COMMAND_TYPE; + pkt->entry_count = (uint8_t)req_cnt; + pkt->sys_define = (uint8_t)ha->req_ring_index; + pkt->handle = (uint32_t)cnt; + + /* Zero out remaining portion of packet. */ + dword_ptr = (uint32_t *)pkt + 2; + for (cnt = 2; cnt < REQUEST_ENTRY_SIZE/4; cnt++) + *dword_ptr++ = 0; + + /* Set ISP command timeout. */ + pkt->timeout = (uint16_t)30; + + /* Set device target ID and LUN */ + pkt->lun = SCSI_LUN_32(cmd); + pkt->target = SCSI_BUS_32(cmd) ? + (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd); + + /* Enable simple tag queuing if device supports it. */ + if (cmd->device->tagged_queue ) + pkt->control_flags |= BIT_3; + + /* Load SCSI command packet. */ + pkt->cdb_len = (uint16_t)CMD_CDBLEN(cmd); + data_ptr = (uint8_t *) &(CMD_CDBP(cmd)); + for (cnt = 0; cnt < pkt->cdb_len; cnt++) + pkt->scsi_cdb[cnt] = *data_ptr++; + DEBUG(printk("Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0])); + /* + * Load data segments. + */ + if (seg_cnt) + { + DEBUG(printk("loading data segments..\n")); + /* Set transfer direction (READ and WRITE) */ + /* Linux doesn't tell us */ + + /* + * 3/10 dg - Normally, we should need this check with our F/W + * but because of a small issue with it we do. + * + * For block devices, cmd->request.cmd has the operation + * For character devices, this isn't always set properly, so + * we need to check data_cmnd[0]. This catches the conditions + * for st.c, but not sg. Generic commands are pass down to us. + */ + if ( (cmd->data_cmnd[0] == WRITE_6) ) + pkt->control_flags |= BIT_6; + else + pkt->control_flags |= (BIT_5|BIT_6); + + sp->dir = pkt->control_flags & (BIT_5|BIT_6); + + /* Set total data segment count. */ + pkt->dseg_count = seg_cnt; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *)&pkt->dseg_0_address; + + if (cmd->use_sg) /* If scatter gather */ + { + DEBUG(qla1280_print("Building S/G data segments..\n\r")); + DEBUG(qla1280_dump_buffer((caddr_t)sg, 4*16 )); + /* Load command entry data segments. */ + for (cnt = 0; cnt < 4 && seg_cnt; cnt++, seg_cnt--) + { + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(sg->address)); + *dword_ptr++ = sg->length; + DEBUG(sprintf(debug_buff,"SG Segment ap=0x%p, len=0x%x\n\r",sg->address,sg->length)); + DEBUG(qla1280_print(debug_buff)); + sg++; + } + /* + * Build continuation packets. + */ + while (seg_cnt > 0) + { + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) + { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } + else + ha->request_ring_ptr++; + + pkt = (cmd_entry_t *)ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for (cnt = 0;cnt < REQUEST_ENTRY_SIZE/4; cnt++) + *dword_ptr++ = 0; + + /* Load packet defaults. */ + ((cont_entry_t *)pkt)->entry_type = + CONTINUE_TYPE; + ((cont_entry_t *)pkt)->entry_count = 1; + + ((cont_entry_t *)pkt)->sys_define = (uint8_t) + ha->req_ring_index; + + /* Setup packet address segment pointer. */ + dword_ptr = (uint32_t *) + &((cont_entry_t *)pkt)->dseg_0_address; + + /* Load continuation entry data segments. */ + for (cnt = 0; cnt < 7 && seg_cnt; cnt++, seg_cnt--) + { + *dword_ptr++ = (u_int) cpu_to_le32(VIRT_TO_BUS(sg->address)); + *dword_ptr++ = sg->length; + sg++; + } +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_32bit_start_scsi: continuation packet data - scsi("); + qla1280_output_number((uint32_t)SCSI_BUS_32(cmd), 10); + qla1280_print(":"); + qla1280_output_number((uint32_t)SCSI_TCN_32(cmd), 10); + qla1280_print(":"); + qla1280_output_number((uint32_t)SCSI_LUN_32(cmd), 10); + qla1280_print(")\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } + } + else /* No scatter gather data transfer */ + { + *dword_ptr++ = (uint32_t) cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer)); + *dword_ptr = (uint32_t) cmd->request_bufflen; + DEBUG(printk("Single Segment ap=0x%p, len=0x%x\n",cmd->request_buffer,cmd->request_bufflen)); + } + } + else /* No data transfer */ + { + *dword_ptr++ = (uint32_t) 0; + *dword_ptr = (uint32_t) 0; +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print( + "qla1280_32bit_start_scsi: No data, command packet data - "); + qla1280_print("\n\r"); + qla1280_dump_buffer((caddr_t)pkt, REQUEST_ENTRY_SIZE); +#endif + } +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_32bit_start_scsi: First IOCB block:\n\r"); + qla1280_dump_buffer((caddr_t)ha->request_ring_ptr, REQUEST_ENTRY_SIZE); +#endif + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) + { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } + else + ha->request_ring_ptr++; + + /* Set chip new ring index. */ + DEBUG(qla1280_print("qla1280_32bit_start_scsi: Wakeup RISC for pending command\n\r")); + ha->qthreads--; + sp->u_start = jiffies; + sp->flags |= SRB_SENT; + ha->actthreads++; + /* qla1280_output_number((uint32_t)ha->actthreads++, 16); */ + WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + } + else + { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING ARRAY\n\r"); + qla1280_print(" req_q_cnt="); + qla1280_output_number((uint32_t)ha->req_q_cnt, 16); + qla1280_print("\n\r"); +#endif + } + } + else + { + status = 1; +#ifdef QL_DEBUG_LEVEL_2 + /* qla1280_print("qla1280_32bit_start_scsi: in-ptr="); + qla1280_output_number((uint32_t)ha->req_ring_index, 16); + qla1280_print(" req_q_cnt="); + qla1280_output_number((uint32_t)ha->req_q_cnt, 16); + qla1280_print(" req_cnt="); + qla1280_output_number((uint32_t)req_cnt, 16); + qla1280_print("\n\r"); */ +#endif + } + + /* Release ring specific lock */ + QLA1280_RING_UNLOCK(ha); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + /* if (status) + qla1280_print("qla1280_32bit_start_scsi: **** FAILED ****\n\r"); */ +#endif +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_32bit_start_scsi"); +#endif + return(status); +} + +/* + * qla1280_req_pkt + * Function is responsible for locking ring and + * getting a zeroed out request packet. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = failed to get slot. + */ +STATIC request_t * +qla1280_req_pkt(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + request_t *pkt = 0; + uint16_t cnt; + uint32_t *dword_ptr; + uint32_t timer; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_req_pkt"); +#endif + + /* Wait for 30 seconds for slot. */ + for (timer = 15000000; timer; timer--) + { + /* Acquire ring specific lock */ + QLA1280_RING_LOCK(ha); + + if (ha->req_q_cnt > 0) + { + /* Calculate number of free request entries. */ + cnt = RD_REG_WORD(®->mailbox4); + if (ha->req_ring_index < cnt) + ha->req_q_cnt = cnt - ha->req_ring_index; + else + ha->req_q_cnt = REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); + } + + /* Found empty request ring slot? */ + if (ha->req_q_cnt > 0) + { + ha->req_q_cnt--; + pkt = ha->request_ring_ptr; + + /* Zero out packet. */ + dword_ptr = (uint32_t *)pkt; + for (cnt = 0; cnt < REQUEST_ENTRY_SIZE/4; cnt++) + *dword_ptr++ = 0; + + /* Set system defined field. */ + pkt->sys_define = (uint8_t)ha->req_ring_index; + + /* Set entry count. */ + pkt->entry_count = 1; + + break; + } + + /* Release ring specific lock */ + QLA1280_RING_UNLOCK(ha); + + SYS_DELAY(2); /* 10 */ + + /* Check for pending interrupts. */ + qla1280_poll(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_req_pkt: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_req_pkt: exiting normally\n\r"); +#endif + return(pkt); +} + +/* + * qla1280_isp_cmd + * Function is responsible for modifying ISP input pointer. + * Releases ring lock. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_isp_cmd(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_isp_cmd"); +#endif + +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_isp_cmd: IOCB data:\n\r"); + qla1280_dump_buffer((caddr_t)ha->request_ring_ptr, REQUEST_ENTRY_SIZE); +#endif + + /* Adjust ring index. */ + ha->req_ring_index++; + if (ha->req_ring_index == REQUEST_ENTRY_CNT) + { + ha->req_ring_index = 0; + ha->request_ring_ptr = ha->request_ring; + } + else + ha->request_ring_ptr++; + + /* Set chip new ring index. */ + WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + + /* Release ring specific lock */ + QLA1280_RING_UNLOCK(ha); + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_isp_cmd"); +#endif +} + +/* + * qla1280_enable_lun + * Issue enable LUN entry IOCB. + * + * Input: + * ha = adapter block pointer. + * b = SCSI BUS number. + * l = LUN number. + */ +STATIC void +qla1280_enable_lun(scsi_qla_host_t *ha, uint8_t b, uint32_t l) +{ + elun_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_enable_lun: entered\n\r"); +#endif + + /* Get request packet. */ + /* + if (pkt = (elun_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = ENABLE_LUN_TYPE; + pkt->lun = (uint16_t)(b ? l | BIT_15 : l); + pkt->command_count = 32; + pkt->immed_notify_count = 1; + pkt->group_6_length = MAX_CMDSZ; + pkt->group_7_length = MAX_CMDSZ; + pkt->timeout = 0x30; + + qla1280_isp_cmd(ha); + } + */ + pkt = (elun_entry_t *)1; + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_enable_lun: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_enable_lun: exiting normally\n\r"); +#endif +} + +#if QL1280_TARGET_MODE_SUPPORT +/****************************************************************************/ +/* Target Mode Support Functions. */ +/****************************************************************************/ + +/* + * qla1280_notify_ack + * Issue notify acknowledge IOCB. + * If sequence ID is zero, acknowledgement of + * SCSI bus reset or bus device reset is assumed. + * + * Input: + * ha = adapter block pointer. + * inotify = immediate notify entry pointer. + */ +STATIC void +qla1280_notify_ack(scsi_qla_host_t *ha, notify_entry_t *inotify) +{ + nack_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_notify_ack: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (nack_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = NOTIFY_ACK_TYPE; + pkt->lun = inotify->lun; + pkt->initiator_id = inotify->initiator_id; + pkt->target_id = inotify->target_id; + if (inotify->seq_id == 0) + pkt->event = BIT_7; + else + pkt->seq_id = inotify->seq_id; + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_notify_ack: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_notify_ack: exiting normally\n\r"); +#endif +} + +/* + * qla1280_immed_notify + * Issue immediate notify IOCB for LUN 0. + * + * Input: + * ha = adapter block pointer. + * inotify = immediate notify entry pointer. + */ +STATIC void +qla1280_immed_notify(scsi_qla_host_t *ha, notify_entry_t *inotify) +{ + notify_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_immed_notify: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (notify_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = IMMED_NOTIFY_TYPE; + pkt->lun = inotify->lun; + pkt->initiator_id = inotify->initiator_id; + pkt->target_id = inotify->target_id; + pkt->status = 1; + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_immed_notify: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_immed_notify: exiting normally\n\r"); +#endif +} + +/* + * qla1280_accept_io + * Issue accept target I/O IOCB for LUN 0. + * + * Input: + * ha = adapter block pointer. + * ctio = ctio returned entry pointer. + */ +STATIC void +qla1280_accept_io(scsi_qla_host_t *ha, ctio_ret_entry_t *ctio) +{ + atio_entry_t *pkt; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_accept_io: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (atio_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = ACCEPT_TGT_IO_TYPE; + pkt->lun = ctio->lun; + pkt->initiator_id = ctio->initiator_id; + pkt->target_id = ctio->target_id; + pkt->tag_value = ctio->tag_value; + pkt->status = 1; + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_accept_io: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_accept_io: exiting normally\n\r"); +#endif +} + +/* + * qla1280_64bit_continue_io + * Issue continue target I/O IOCB. + * + * Input: + * ha = adapter block pointer. + * atio = atio pointer. + * len = total bytecount. + * addr = physical address pointer. + */ +STATIC void +qla1280_64bit_continue_io(scsi_qla_host_t *ha, atio_entry_t *atio, uint32_t len, + paddr32_t *addr) +{ + ctio_a64_entry_t *pkt; + uint32_t *dword_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_64bit_continue_io: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (ctio_a64_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = CTIO_A64_TYPE; + pkt->lun = atio->lun; + pkt->initiator_id = atio->initiator_id; + pkt->target_id = atio->target_id; + pkt->option_flags = atio->option_flags; + pkt->tag_value = atio->tag_value; + pkt->scsi_status = atio->scsi_status; + + if (len) + { + pkt->dseg_count = 1; + pkt->transfer_length = len; + pkt->dseg_0_length = len; + dword_ptr = (uint32_t *)addr; + pkt->dseg_0_address[0] = *dword_ptr++; + pkt->dseg_0_address[1] = *dword_ptr; + } + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_64bit_continue_io: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_64bit_continue_io: exiting normally\n\r"); +#endif +} + +/* + * qla1280_32bit_continue_io + * Issue continue target I/O IOCB. + * + * Input: + * ha = adapter block pointer. + * atio = atio pointer. + * len = total bytecount. + * addr = physical address pointer. + */ +STATIC void +qla1280_32bit_continue_io(scsi_qla_host_t *ha, atio_entry_t *atio, uint32_t len, + paddr32_t *addr) +{ + ctio_entry_t *pkt; + uint32_t *dword_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_32bit_continue_io: entered\n\r"); +#endif + + /* Get request packet. */ + if (pkt = (ctio_entry_t *)qla1280_req_pkt(ha)) + { + pkt->entry_type = CONTINUE_TGT_IO_TYPE; + pkt->lun = atio->lun; + pkt->initiator_id = atio->initiator_id; + pkt->target_id = atio->target_id; + pkt->option_flags = atio->option_flags; + pkt->tag_value = atio->tag_value; + pkt->scsi_status = atio->scsi_status; + + if (len) + { + pkt->dseg_count = 1; + pkt->transfer_length = len; + pkt->dseg_0_length = len; + dword_ptr = (uint32_t *)addr; + pkt->dseg_0_address = *dword_ptr; + } + + /* Issue command to ISP */ + qla1280_isp_cmd(ha); + } + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + if (!pkt) + qla1280_print("qla1280_32bit_continue_io: **** FAILED ****\n\r"); +#endif +#ifdef QL_DEBUG_LEVEL_3 + else + qla1280_print("qla1280_32bit_continue_io: exiting normally\n\r"); +#endif +} +#endif /* QL1280_TARGET_MODE_SUPPORT */ + +/****************************************************************************/ +/* Interrupt Service Routine. */ +/****************************************************************************/ + +/**************************************************************************** + * qla1280_isr + * Calls I/O done on command completion. + * + * Input: + * ha = adapter block pointer. + * done_q_first = done queue first pointer. + * done_q_last = done queue last pointer. + * INTR_LOCK must be already obtained. + ****************************************************************************/ +STATIC void +qla1280_isr(scsi_qla_host_t *ha, srb_t **done_q_first, srb_t **done_q_last) +{ + device_reg_t *reg = ha->iobase; + response_t *pkt; + srb_t *sp; + uint16_t mailbox[MAILBOX_REGISTER_COUNT]; + uint16_t *wptr; + uint32_t index; + + ENTER("qla1280_isr"); + + + /* Save mailbox register 5 */ + mailbox[5] = RD_REG_WORD(®->mailbox5); + + /* Check for mailbox interrupt. */ + + mailbox[0] = RD_REG_WORD(®->semaphore); + if (mailbox[0] & BIT_0) + { + /* Get mailbox data. */ + + wptr = &mailbox[0]; + *wptr++ = RD_REG_WORD(®->mailbox0); + *wptr++ = RD_REG_WORD(®->mailbox1); + *wptr = RD_REG_WORD(®->mailbox2); + if (mailbox[0] != MBA_SCSI_COMPLETION) + { + wptr++; + *wptr++ = RD_REG_WORD(®->mailbox3); + *wptr++ = RD_REG_WORD(®->mailbox4); + wptr++; + *wptr++ = RD_REG_WORD(®->mailbox6); + *wptr = RD_REG_WORD(®->mailbox7); + } + + /* Release mailbox registers. */ + + WRT_REG_WORD(®->semaphore, 0); + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_isr: mailbox interrupt mailbox[0] = "); + qla1280_output_number((uint32_t)mailbox[0], 16); + qla1280_print("\n\r"); +#endif + + /* Handle asynchronous event */ + + switch (mailbox[0]) + { + case MBA_SCSI_COMPLETION: /* Response completion */ +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_isr: mailbox response completion\n\r"); +#endif + if (ha->flags.online) + { + /* Get outstanding command index. */ + index = (uint32_t)(mailbox[2] << 16 | mailbox[1]); + + /* Validate handle. */ + if (index < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[index]; + else + sp = 0; + + if (sp) + { + /* Free outstanding command slot. */ + ha->outstanding_cmds[index] = 0; + + /* Save ISP completion status */ + CMD_RESULT(sp->cmd) = 0; + + /* Place block on done queue */ + sp->s_next = NULL; + sp->s_prev = *done_q_last; + if (!*done_q_first) + *done_q_first = sp; + else + (*done_q_last)->s_next = sp; + *done_q_last = sp; + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: ISP invalid handle\n\r"); +#endif + printk(KERN_WARNING "qla1280: ISP invalid handle"); + ha->flags.isp_abort_needed = TRUE; + } + } + break; + case MBA_BUS_RESET: /* SCSI Bus Reset */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: asynchronous BUS_RESET\n\r"); +#endif + ha->flags.reset_marker = TRUE; + index = mailbox[6] & BIT_0; + ha->bus_settings[index].reset_marker = TRUE; + break; + case MBA_SYSTEM_ERR: /* System Error */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: ISP System Error - mbx1="); + qla1280_output_number((uint32_t)mailbox[1], 16); + qla1280_print(", mbx2="); + qla1280_output_number((uint32_t)mailbox[2], 16); + qla1280_print(", mbx3="); + qla1280_output_number((uint32_t)mailbox[3], 16); + qla1280_print("\n\r"); +#endif + printk(KERN_WARNING + "qla1280: ISP System Error - mbx1=%xh, mbx2=%xh, mbx3=%xh\n", + mailbox[1], mailbox[2], mailbox[3]); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: ISP Request Transfer Error\n\r"); +#endif + printk(KERN_WARNING "qla1280: ISP Request Transfer Error\n"); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: ISP Response Transfer Error\n\r"); +#endif + printk(KERN_WARNING "qla1280: ISP Response Transfer Error\n"); + ha->flags.isp_abort_needed = TRUE; + break; + case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: asynchronous WAKEUP_THRES\n\r"); +#endif + break; + case MBA_TIMEOUT_RESET: /* Execution Timeout Reset */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: asynchronous TIMEOUT_RESET\n\r"); +#endif + break; + case MBA_DEVICE_RESET: /* Bus Device Reset */ +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_isr: asynchronous BUS_DEVICE_RESET\n\r"); +#endif + ha->flags.reset_marker = TRUE; + index = mailbox[6] & BIT_0; + ha->bus_settings[index].reset_marker = TRUE; + break; + case MBA_BUS_MODE_CHANGE: +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print( + "qla1280_isr: asynchronous BUS_MODE_CHANGE\n\r"); +#endif + break; + default: + if (mailbox[0] < MBA_ASYNC_EVENT) + { + wptr = &mailbox[0]; + ha->mailbox_out[0] = *wptr++; + ha->mailbox_out[1] = *wptr++; + ha->mailbox_out[2] = *wptr++; + ha->mailbox_out[3] = *wptr++; + ha->mailbox_out[4] = *wptr++; + ha->mailbox_out[5] = *wptr++; + ha->mailbox_out[6] = *wptr++; + ha->mailbox_out[7] = *wptr; + ha->flags.mbox_int = TRUE; + } + break; + } + } + else + WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); + + /* + * Response ring + */ + if (ha->flags.online && !ha->flags.mbox_busy) + { + if (mailbox[5] < RESPONSE_ENTRY_CNT) + { + while (ha->rsp_ring_index != mailbox[5]) + { + pkt = ha->response_ring_ptr; + +#ifdef QL_DEBUG_LEVEL_5 + qla1280_print("qla1280_isr: ha->rsp_ring_index = "); + qla1280_output_number((uint32_t)ha->rsp_ring_index, 16); + qla1280_print(" mailbox[5] = "); + qla1280_output_number((uint32_t)mailbox[5], 16); + qla1280_print("\n\rqla1280_isr: response packet data\n\r"); + qla1280_dump_buffer((caddr_t)pkt, RESPONSE_ENTRY_SIZE); +#endif + +#if defined(QL_DEBUG_LEVEL_2) && !defined(QL_DEBUG_LEVEL_5) + if (pkt->entry_type == STATUS_TYPE) + { + if ((uint8_t)(pkt->scsi_status) || pkt->comp_status || + pkt->entry_status) + { + DEBUG(qla1280_print("qla1280_isr: ha->rsp_ring_index = ");) + DEBUG(qla1280_output_number((uint32_t)ha->rsp_ring_index, + 16);) + DEBUG(qla1280_print(" mailbox[5] = ");) + DEBUG(qla1280_output_number((uint32_t)mailbox[5], 16);) + DEBUG(qla1280_print( "\n\r comp_status = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->comp_status,16);) + DEBUG(qla1280_print( ", ");) + DEBUG(qla1280_print( " scsi_status = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->scsi_status,16);) + DEBUG(qla1280_print( "\n\r");) + /* qla1280_print( + "\n\rqla1280_isr: response packet data\n\r"); + qla1280_dump_buffer((caddr_t)pkt, + RESPONSE_ENTRY_SIZE); */ + } + } + else + { + qla1280_print("qla1280_isr: ha->rsp_ring_index = "); + qla1280_output_number((uint32_t)ha->rsp_ring_index, 16); + qla1280_print(" mailbox[5] = "); + qla1280_output_number((uint32_t)mailbox[5], 16); + qla1280_print( + "\n\rqla1280_isr: response packet data\n\r"); + qla1280_dump_buffer((caddr_t)pkt, RESPONSE_ENTRY_SIZE); + } +#endif + if (pkt->entry_type == STATUS_TYPE || pkt->entry_status) + { + if (pkt->entry_type == STATUS_TYPE) + qla1280_status_entry(ha, (sts_entry_t *)pkt, + done_q_first, done_q_last); + else + qla1280_error_entry(ha, pkt, + done_q_first, done_q_last); + + /* Adjust ring index. */ + ha->rsp_ring_index++; + if (ha->rsp_ring_index == RESPONSE_ENTRY_CNT) + { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } + else + ha->response_ring_ptr++; + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + } +#if QLA1280_TARGET_MODE_SUPPORT + else + { + pkt = &response_entry; + + /* Copy packet. */ + dptr1 = (uint32_t *)ha->response_ring_ptr; + dptr2 = (uint32_t *)pkt; + for (index = 0; index < RESPONSE_ENTRY_SIZE/4; index++) + *dptr2++ = *dptr1++; + + /* Adjust ring index. */ + ha->rsp_ring_index++; + if (ha->rsp_ring_index == RESPONSE_ENTRY_CNT) + { + ha->rsp_ring_index = 0; + ha->response_ring_ptr = ha->response_ring; + } + else + ha->response_ring_ptr++; + WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); + + /* Release interrupt specific lock */ + QLA1280_INTR_UNLOCK(ha); + + switch (pkt->entry_type) + { + case ACCEPT_TGT_IO_TYPE: + qla1280_atio_entry(ha, (atio_entry_t *)pkt); + break; + case IMMED_NOTIFY_TYPE: + qla1280_notify_entry(ha, (notify_entry_t *)pkt); + break; + case CTIO_RET_TYPE: + qla1280_accept_io(ha, (ctio_ret_entry_t *)pkt); + break; + default: + break; + } + + /* Acquire interrupt specific lock */ + QLA1280_INTR_LOCK(ha); + } +#endif + } + } + else + { + ha->flags.isp_abort_needed = TRUE; +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_isr: Response pointer Error\n"); +#endif + } + } + + LEAVE("qla1280_isr"); +} + +/* + * qla1280_rst_aen + * Processes asynchronous reset. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_rst_aen(scsi_qla_host_t *ha) +{ +#if QL1280_TARGET_MODE_SUPPORT + notify_entry_t nentry; +#endif + uint8_t b; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_rst_aen"); +#endif + + if (ha->flags.online && !ha->flags.reset_active && + !ha->flags.abort_isp_active) + { + ha->flags.reset_active = TRUE; + while (ha->flags.reset_marker) + { + /* Issue marker command. */ + ha->flags.reset_marker = FALSE; + for (b = 0; b < ha->ports && !ha->flags.reset_marker; b++) + { + if (ha->bus_settings[b].reset_marker) + { + ha->bus_settings[b].reset_marker = FALSE; + qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL); + + if (!ha->flags.reset_marker) + { +#if QL1280_TARGET_MODE_SUPPORT + /* Issue notify acknowledgement command. */ + bzero((caddr_t)&nentry, sizeof(notify_entry_t)); + + nentry.initiator_id = nentry.target_id = b ? + ha->bus_settings[b].id | BIT_7 : + ha->bus_settings[b].id; + qla1280_notify_entry(ha, &nentry); +#endif + + /* Asynchronous event notification */ + } + } + } + } + } + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_rst_aen"); +#endif +} + +#if QL1280_TARGET_MODE_SUPPORT +/* + * qla1280_atio_entry + * Processes received ISP accept target I/O entry. + * + * Input: + * ha = adapter block pointer. + * pkt = entry pointer. + */ +STATIC void +qla1280_atio_entry(scsi_qla_host_t *ha, atio_entry_t *pkt) +{ + uint64_t *a64; + uint64_t *end_a64; + paddr32_t phy_addr[2]; + paddr32_t end_addr[2]; + uint32_t len; + uint32_t offset; + uint8_t t; + uint8_t *sense_ptr; + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: entered\n\r"); +#endif + + t = pkt->initiator_id; + sense_ptr = ha->tsense + t * TARGET_SENSE_SIZE; + a64 = (uint64_t *)&phy_addr[0]; + end_a64 = (uint64_t *)&end_addr[0]; + + switch (pkt->status & ~BIT_7) + { + case 7: /* Path invalid */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_atio_entry: Path invalid\n\r"); +#endif + break; + case 0x14: /* Target Bus Phase Sequence Failure */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print( + "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r"); +#endif + if (pkt->status & BIT_7) + { + BCOPY((caddr_t)&pkt->sense_data, sense_ptr,TARGET_SENSE_SIZE); + } + else + { + bzero(sense_ptr, TARGET_SENSE_SIZE); + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_HARDERR; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_SELFAIL; + } + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | (uint32_t)OF_NO_DATA; + if (ha->flags.enable_64bit_addressing) + qla1280_64bit_continue_io(ha, pkt, 0, 0); + else + qla1280_32bit_continue_io(ha, pkt, 0, 0); + break; + case 0x16: /* Requested Capability Not Available */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print( + "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r"); +#endif + break; + case 0x17: /* Bus Device Reset Message Received */ +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print( + "qla1280_atio_entry: Target Bus Phase Sequence Failure\n\r"); +#endif + break; + case 0x3D: /* CDB Received */ + + /* Check for invalid LUN */ + if (pkt->lun && pkt->cdb[0] != SS_INQUIR && + pkt->cdb[0] != SS_REQSEN) + pkt->cdb[0] = SS_TEST; + + switch (pkt->cdb[0]) + { + case SS_TEST: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SS_TEST\n\r"); +#endif + bzero(sense_ptr, TARGET_SENSE_SIZE); + len = 0; + if (pkt->lun == 0) + pkt->scsi_status = S_GOOD; + else + { + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_INVLUN; + pkt->scsi_status = S_CKCON; + } + + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + break; + case SS_REQSEN: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SS_REQSEN\n\r"); +#endif + phy_addr[0] = ha->tsense_dma; + phy_addr[1] = 0; + *a64 += t * TARGET_SENSE_SIZE; + if (pkt->cdb[4] > TARGET_SENSE_SIZE) + len = TARGET_SENSE_SIZE; + else + len = pkt->cdb[4]; + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + break; + case SS_INQUIR: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SS_INQUIR\n\r"); +#endif + bzero(sense_ptr, TARGET_SENSE_SIZE); + phy_addr[0] = ha->tbuf_dma; + phy_addr[1] = 0; + *a64 += TARGET_INQ_OFFSET; + + if (pkt->lun == 0) + { + ha->tbuf->inq.id_type = ID_PROCESOR; + ha->tbuf->inq.id_pqual = ID_QOK; + } + else + { + ha->tbuf->inq.id_type = ID_NODEV; + ha->tbuf->inq.id_pqual = ID_QNOLU; + } + + if (pkt->cdb[4] > sizeof(struct ident)) + len = sizeof(struct ident); + else + len = pkt->cdb[4]; + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + break; + case SM_WRDB: + bzero(sense_ptr, TARGET_SENSE_SIZE); + offset = pkt->cdb[5]; + offset |= pkt->cdb[4] << 8; + offset |= pkt->cdb[3] << 16; + len = pkt->cdb[8]; + len |= pkt->cdb[7] << 8; + len |= pkt->cdb[6] << 16; + end_addr[0] = phy_addr[0] = ha->tbuf_dma; + end_addr[1] = phy_addr[1] = 0; + *end_a64 += TARGET_DATA_OFFSET + TARGET_DATA_SIZE; + switch (pkt->cdb[1] & 7) + { + case RW_BUF_HDATA: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_HDATA\n\r"); +#endif + if (len > TARGET_DATA_SIZE + 4) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB, length > buffer size\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + len = 0; + } + else if (len) + { + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_OUT; +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: Issuing SDI_TARMOD_WRCOMP\n\r"); +#endif + sdi_xaen(SDI_TARMOD_WRCOMP, ha->cntlr, + pkt->target_id, pkt->lun, 0, offset); + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + + break; + case RW_BUF_DATA: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_DATA\n\r"); +#endif + *a64 += offset + TARGET_DATA_OFFSET; + if (pkt->cdb[2] != 0 || *a64 >= *end_a64 || + *a64 + len > *end_a64) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB, RW_BUF_DATA BAD\n\r"); + qla1280_print("buf_id="); + qla1280_output_number((uint32_t)pkt->cdb[2], 16); + qla1280_print(", offset="); + qla1280_output_number((uint32_t)offset, 16); + qla1280_print(", length="); + qla1280_output_number((uint32_t)len, 16); + qla1280_print("\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + else if (len) + { + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_OUT; +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: Issuing SDI_TARMOD_WRCOMP\n\r"); +#endif + sdi_xaen(SDI_TARMOD_WRCOMP, ha->cntlr, + pkt->target_id, pkt->lun, 0, offset); + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_WRDB unknown mode\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + break; + } + break; + case SM_RDDB: + bzero(sense_ptr, TARGET_SENSE_SIZE); + offset = pkt->cdb[5]; + offset |= pkt->cdb[4] << 8; + offset |= pkt->cdb[3] << 16; + len = pkt->cdb[8]; + len |= pkt->cdb[7] << 8; + len |= pkt->cdb[6] << 16; + end_addr[0] = phy_addr[0] = ha->tbuf_dma; + end_addr[1] = phy_addr[1] = 0; + *end_a64 += TARGET_DATA_OFFSET + TARGET_DATA_SIZE; + switch (pkt->cdb[1] & 7) + { + case RW_BUF_HDATA: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_HDATA\n\r"); +#endif + if (len) + { + ha->tbuf->hdr[0] = 0; + ha->tbuf->hdr[1] = + (uint8_t)(TARGET_DATA_SIZE >> 16); + ha->tbuf->hdr[2] = + (uint8_t)(TARGET_DATA_SIZE >> 8); + ha->tbuf->hdr[3] = (uint8_t)TARGET_DATA_SIZE; + if (len > TARGET_DATA_SIZE + 4) + len = TARGET_DATA_SIZE + 4; + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + break; + case RW_BUF_DATA: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DATA\n\r"); +#endif + *a64 += offset + TARGET_DATA_OFFSET; + if (pkt->cdb[2] != 0 || *a64 >= *end_a64) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DATA BAD\n\r"); + qla1280_print("buf_id="); + qla1280_output_number((uint32_t)pkt->cdb[2], 16); + qla1280_print(", offset="); + qla1280_output_number((uint32_t)offset, 16); + qla1280_print("\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + else + { + if (*a64 + len > *end_a64) + len = *end_a64 - *a64; + if (len) + { + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + } + break; + case RW_BUF_DESC: +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: SM_RDDB, RW_BUF_DESC\n\r"); +#endif + if (len) + { + if (len > 4) + len = 4; + + ha->tbuf->hdr[0] = 0; + if (pkt->cdb[2] != 0) + { + ha->tbuf->hdr[1] = 0; + ha->tbuf->hdr[2] = 0; + ha->tbuf->hdr[3] = 0; + } + else + { + ha->tbuf->hdr[1] = + (uint8_t)(TARGET_DATA_SIZE >> 16); + ha->tbuf->hdr[2] = + (uint8_t)(TARGET_DATA_SIZE >> 8); + ha->tbuf->hdr[3] = + (uint8_t)TARGET_DATA_SIZE; + } + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_DATA_IN; + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB, zero length\n\r"); +#endif + pkt->scsi_status = S_GOOD; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: SM_RDDB unknown mode\n\r"); +#endif + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_ILLCDB; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + break; + } + break; + default: +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_atio_entry: Unknown SCSI command\n\r"); + qla1280_dump_buffer((caddr_t)&pkt->cdb[0], pkt->cdb_len); +#endif + bzero(sense_ptr, TARGET_SENSE_SIZE); + *sense_ptr = 0x70; + *(sense_ptr+2) = SD_ILLREQ; + *(sense_ptr+7) = TARGET_SENSE_SIZE-8; + *(sense_ptr+12) = SC_INVOPCODE; + len = 0; + pkt->scsi_status = S_CKCON; + pkt->option_flags |= (uint32_t)OF_SSTS | + (uint32_t)OF_NO_DATA; + break; + } + if (ha->flags.enable_64bit_addressing) + qla1280_64bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr); + else + qla1280_32bit_continue_io(ha, pkt, len, (paddr32_t *)&phy_addr); + break; + default: + break; + } + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_atio_entry: exiting normally\n\r"); +#endif +} + +/* + * qla1280_notify_entry + * Processes received ISP immediate notify entry. + * + * Input: + * ha = adapter block pointer. + * pkt = entry pointer. + */ +STATIC void +qla1280_notify_entry(scsi_qla_host_t *ha, notify_entry_t *pkt) +{ +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_notify_entry: entered\n\r"); +#endif + + /* Acknowledge immediate notify */ + qla1280_notify_ack(ha, pkt); + + /* Issue notify entry to increment resource count */ + qla1280_immed_notify(ha, pkt); + +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_notify_entry: exiting normally\n\r"); +#endif +} + +#endif /* QLA1280_TARGET_MODE_SUPPORT */ +/* + * qla1280_status_entry + * Processes received ISP status entry. + * + * Input: + * ha = adapter block pointer. + * pkt = entry pointer. + * done_q_first = done queue first pointer. + * done_q_last = done queue last pointer. + */ +STATIC void +qla1280_status_entry(scsi_qla_host_t *ha, sts_entry_t *pkt, srb_t **done_q_first, + srb_t **done_q_last) +{ + uint32_t b, t, l; + uint8_t sense_sz = 0; + srb_t *sp; + scsi_lu_t *q; + Scsi_Cmnd *cp; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_status_entry"); +#endif + + /* Validate handle. */ + if (pkt->handle < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[pkt->handle]; + else + sp = 0; + + if (sp) + { + /* Free outstanding command slot. */ + ha->outstanding_cmds[pkt->handle] = 0; + + cp = sp->cmd; + /* Generate LU queue on cntrl, target, LUN */ + b = SCSI_BUS_32(cp); + t = SCSI_TCN_32(cp); + l = SCSI_LUN_32(cp); + q = LU_Q(ha, b, t, l); + if( pkt->comp_status || pkt->scsi_status ) + { + DEBUG(qla1280_print( "scsi: comp_status = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->comp_status,16);) + DEBUG(qla1280_print( ", ");) + DEBUG(qla1280_print( " scsi_status = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->scsi_status,16);) + DEBUG(qla1280_print( "\n\r");) + DEBUG(qla1280_print(", handle = ");) + DEBUG(qla1280_output_number((uint32_t)pkt->handle, 16);) + DEBUG(qla1280_print("\n\r");) + } + + /* Target busy */ + if ( pkt->scsi_status & SS_BUSY_CONDITION && + pkt->scsi_status != SS_RESERVE_CONFLICT ) + { + CMD_RESULT(cp) = (int) (DID_BUS_BUSY << 16) | + (pkt->scsi_status & 0xff); + } + else + { + + /* Save ISP completion status */ + CMD_RESULT(cp) = qla1280_return_status( pkt, cp ); + + if (pkt->scsi_status & SS_CHECK_CONDITION) + { + BZERO(cp->sense_buffer, CMD_SNSLEN(cp)); + if (pkt->comp_status != CS_ARS_FAILED) + { + if ( pkt->req_sense_length < CMD_SNSLEN(cp) ) + sense_sz = pkt->req_sense_length; + else + sense_sz = CMD_SNSLEN(cp) - 1; + + BCOPY((caddr_t)&pkt->req_sense_data, cp->sense_buffer, sense_sz); + + } +#ifdef QL_DEBUG_LEVEL_2 + DEBUG(qla1280_print( + "qla1280_status_entry: Check condition Sense data, b");) + DEBUG(qla1280_output_number((uint32_t)b, 10);) + DEBUG(qla1280_print("t");) + DEBUG(qla1280_output_number((uint32_t)t, 10);) + DEBUG(qla1280_print("d");) + DEBUG(qla1280_output_number((uint32_t)l, 10);) + DEBUG(qla1280_print("\n\r");) + DEBUG(if (sense_sz)) + DEBUG(qla1280_dump_buffer(cp->sense_buffer, sense_sz);) +#endif + } + } + /* Place command on done queue. */ + qla1280_done_q_put(sp, done_q_first, done_q_last); + } + else + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_status_entry: ISP Invalid handle\n\r"); +#endif + printk(KERN_WARNING "qla1280: Status Entry invalid handle\n"); + ha->flags.isp_abort_needed = TRUE; + } +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_status_entry"); +#endif +} + +/* + * qla1280_error_entry + * Processes error entry. + * + * Input: + * ha = adapter block pointer. + * pkt = entry pointer. + * done_q_first = done queue first pointer. + * done_q_last = done queue last pointer. + */ +STATIC void +qla1280_error_entry(scsi_qla_host_t *ha, response_t *pkt, srb_t **done_q_first, + srb_t **done_q_last) +{ + srb_t *sp; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_error_entry"); +#endif + +#ifdef QL_DEBUG_LEVEL_2 + if (pkt->entry_status & BIT_3) + qla1280_print("qla1280_error_entry: BAD PAYLOAD flag error\n\r"); + else if (pkt->entry_status & BIT_2) + qla1280_print("qla1280_error_entry: BAD HEADER flag error\n\r"); + else if (pkt->entry_status & BIT_1) + qla1280_print("qla1280_error_entry: FULL flag error\n\r"); + else + qla1280_print("qla1280_error_entry: UNKNOWN flag error\n\r"); +#endif + + /* Validate handle. */ + if (pkt->handle < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[pkt->handle]; + else + sp = 0; + + if (sp) + { + /* Free outstanding command slot. */ + ha->outstanding_cmds[pkt->handle] = 0; + + /* Bad payload or header */ + if (pkt->entry_status & (BIT_3 + BIT_2)) + { + /* Bad payload or header, set error status. */ + /* CMD_RESULT(sp->cmd) = CS_BAD_PAYLOAD; */ + CMD_RESULT(sp->cmd) = (int) DID_ERROR << 16; + } + else if (pkt->entry_status & BIT_1 ) /* FULL flag */ + { + CMD_RESULT(sp->cmd) = (int) DID_BUS_BUSY << 16; + } + else + { + /* Set error status. */ + CMD_RESULT(sp->cmd) =(int) DID_ERROR << 16; + } + /* Place command on done queue. */ + qla1280_done_q_put(sp, done_q_first, done_q_last); + } +#if QLA1280_64BIT_SUPPORT + else if (pkt->entry_type == COMMAND_A64_TYPE) + { +#ifdef QL_DEBUG_LEVEL_2 + qla1280_print("qla1280_error_entry: ISP Invalid handle\n\r"); +#endif + printk(KERN_WARNING "!qla1280: Error Entry invalid handle"); + ha->flags.isp_abort_needed = TRUE; + } +#endif + +#ifdef QL_DEBUG_LEVEL_3 + LEAVE("qla1280_error_entry"); +#endif +} + +/* + * qla1280_abort_isp + * Resets ISP and aborts all outstanding commands. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + * 0 = success + */ +STATIC uint8_t +qla1280_abort_isp(scsi_qla_host_t *ha) +{ + device_reg_t *reg = ha->iobase; + uint8_t status = 0; + uint16_t cnt; + srb_t *sp; + scsi_lu_t *q; + uint32_t b, t, l; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_abort_isp"); +#endif + + DRIVER_LOCK + ha->flags.isp_abort_needed = FALSE; + if (!ha->flags.abort_isp_active && ha->flags.online) + { + ha->flags.abort_isp_active = TRUE; + + /* Disable ISP interrupts. */ + WRT_REG_WORD(®->ictrl, 0); + + /* Dequeue all commands in outstanding command list. */ + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) + { + sp = ha->outstanding_cmds[cnt]; + if (sp) + { + ha->outstanding_cmds[cnt] = 0; + + /* Generate LU queue on controller, target, LUN */ + b = SCSI_BUS_32(sp->cmd); + t = SCSI_TCN_32(sp->cmd); + l = SCSI_LUN_32(sp->cmd); + + q = (scsi_lu_t *)LU_Q(ha, b, t, l); + + /* Reset outstanding command count. */ + q->q_outcnt = 0; + q->q_flag &= ~QLA1280_QBUSY; + q->q_flag = 0; + + /* Adjust watchdog timer for command. */ + /* if (sp->flags & SRB_WATCHDOG) + sp->timeout += 2; */ + + /* Place request back on top of device queue. */ + /* sp->flags &= ~(SRB_SENT | SRB_TIMEOUT); */ + sp->flags = 0; + qla1280_putq_t(q, sp); + } + } + + /* If firmware needs to be loaded */ + if (qla1280_isp_firmware(ha)) + { + if (!(status = qla1280_chip_diag(ha))) + status = qla1280_setup_chip(ha); + } + + if (!status) + { + /* Setup adapter based on NVRAM parameters. */ + qla1280_nvram_config(ha); + + if (!(status = qla1280_init_rings(ha))) + { + /* Issue SCSI reset. */ + for (b = 0; b < ha->ports; b++) + { + qla1280_bus_reset(ha, b); + } + do + { + /* Issue marker command. */ + ha->flags.reset_marker = FALSE; + for (b = 0; b < ha->ports; b++) + { + ha->bus_settings[b].reset_marker = FALSE; + qla1280_marker(ha, b, 0, 0, MK_SYNC_ALL); + } + }while (ha->flags.reset_marker); + + /* Enable host adapter target mode. */ + for (b = 0; b < ha->ports; b++) + { + if (!(status = qla1280_enable_tgt(ha, b))) + { + for (cnt = 0; cnt < MAX_LUNS; cnt++) + { + /* qla1280_enable_lun(ha, b, cnt); */ + qla1280_poll(ha); + } + } + else + break; + } + + if (!status) + { + /* Enable ISP interrupts. */ + WRT_REG_WORD(®->ictrl, ISP_EN_INT + ISP_EN_RISC); + ha->flags.abort_isp_active = FALSE; + /* Restart queues that may have been stopped. */ + qla1280_restart_queues(ha); + } + } + } + } + + if (status) + { + printk(KERN_WARNING + "qla1280: ISP error recovery failed, board disabled"); + qla1280_reset_adapter(ha); + qla1280_abort_queues(ha); + +#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) + qla1280_print("qla1280_abort_isp: **** FAILED ****\n\r"); +#endif + } +#ifdef QL_DEBUG_LEVEL_3 + else + LEAVE("qla1280_abort_isp"); +#endif + DRIVER_UNLOCK + + return(status); +} + +/* + * qla1280_restart_queues + * Restart all device queues. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_restart_queues(scsi_qla_host_t *ha) +{ + scsi_lu_t *q; + uint32_t b, t, l; + +#ifdef QL_DEBUG_LEVEL_3 + ENTER("qla1280_restart_queues"); +#endif + + for (b = 0; b < ha->ports; b++) + for (t = 0; t < MAX_TARGETS; t++) + for (l = 0; l < MAX_LUNS; l++) + { + q = (scsi_lu_t *) LU_Q(ha, b, t, l); + if (q != NULL) + { + /* Acquire LU queue specific lock */ + QLA1280_SCSILU_LOCK(q); + + if (q->q_first) + qla1280_next(ha, q, b); + else + /* Release LU queue specific lock */ + QLA1280_SCSILU_UNLOCK(q); + } + } +#ifdef QL_DEBUG_LEVEL_3 + qla1280_print("qla1280_restart_queues: exiting normally\n"); +#endif +} + +/* + * qla1280_abort_queue_single + * Abort all commands on a device queues. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void qla1280_abort_queue_single(scsi_qla_host_t *ha,uint32_t b,uint32_t t,uint32_t l,uint32_t stat) +{ + scsi_lu_t *q; + srb_t *sp, *sp_next; + + ENTER("qla1280_abort_queue_single"); + q = (scsi_lu_t * )LU_Q(ha, b, t, l); + if (q != NULL) + { + /* Acquire LU queue specific lock */ + QLA1280_SCSILU_LOCK(q); + + sp = q->q_first; + q->q_first = q->q_last = NULL; + + QLA1280_SCSILU_UNLOCK(q); + + while (sp) + { + sp_next = sp->s_next; + CMD_RESULT(sp->cmd) = stat; + qla1280_done_q_put(sp, (srb_t **)&ha->done_q_first, (srb_t **)&ha->done_q_last); + sp = sp_next; + } + } + LEAVE("qla1280_abort_queue_single"); +} + +/* + * qla1280_abort_queues + * Abort all commands on device queues. + * + * Input: + * ha = adapter block pointer. + */ +STATIC void +qla1280_abort_queues(scsi_qla_host_t *ha) +{ + uint32_t b, t, l; + + ENTER("qla1280_abort_queues"); + + for (b = 0; b < ha->ports; b++) + for (t = 0; t < MAX_TARGETS; t++) + for (l = 0; l < MAX_LUNS; l++) + qla1280_abort_queue_single(ha,b,t,l,DID_RESET); + + LEAVE("qla1280_abort_queues"); +} + +/* + * qla1280_debounce_register + * Debounce register. + * + * Input: + * port = register address. + * + * Returns: + * register value. + */ +STATIC uint16_t +qla1280_debounce_register(volatile uint16_t *addr) +{ + volatile uint16_t ret; + volatile uint16_t ret2; + + do + { + ret = RD_REG_WORD(addr); + ret2 = RD_REG_WORD(addr); + }while (ret != ret2); + + return(ret); +} + + +/* + * Declarations for load module + */ +#ifdef MODULE +Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; + +#include "scsi_module.c" +#endif + +/************************************************************************ + * qla1280_check_for_dead_scsi_bus * + * * + * This routine checks for a dead SCSI bus * + ************************************************************************/ +#define SET_SXP_BANK 0x0100 +#define SCSI_PHASE_INVALID 0x87FF +int qla1280_check_for_dead_scsi_bus(scsi_qla_host_t *ha, srb_t *sp) +{ + uint16_t config_reg, scsi_control; + device_reg_t *reg = ha->iobase; + uint32_t b; + Scsi_Cmnd *cp; + + /* + * If SCSI Bus is Dead because of bad termination, + * we will return a status of Selection timeout. + */ + + cp = sp->cmd; + b = SCSI_BUS_32(cp); + if (ha->bus_settings[b].scsi_bus_dead) + { + WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); + config_reg = RD_REG_WORD(®->cfg_1); + WRT_REG_WORD(®->cfg_1,SET_SXP_BANK); + scsi_control = RD_REG_WORD(®->scsiControlPins); + WRT_REG_WORD(®->cfg_1,config_reg); + WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); + + if (scsi_control == SCSI_PHASE_INVALID) + { + CMD_RESULT(cp) = DID_NO_CONNECT << 16; + CMD_HANDLE(cp) = (unsigned char *) 0; + /* ha->actthreads--; */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + sti(); + (*(cp)->scsi_done)(cp); + cli(); +#else + (*(cp)->scsi_done)(cp); +#endif + return(TRUE); /* bus is dead */ + } + else + { + ha->bus_settings[b].scsi_bus_dead = FALSE; + ha->bus_settings[b].failed_reset_count= 0; + } + } + return(FALSE); /* bus is not dead */ +} + +STATIC uint8_t +qla12160_set_target_parameters(scsi_qla_host_t *ha, uint32_t b, uint32_t t, uint32_t l, nvram160_t *nv) +{ + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + /* Set Target Parameters. */ + mb[0] = MBC_SET_TARGET_PARAMETERS; + mb[1] = (uint16_t)(b ? t | BIT_7 :t); + mb[1] <<= 8; + mb[2] = nv->bus[b].target[t].parameter.c << 8; + mb[2] |= TP_AUTO_REQUEST_SENSE; + mb[2] &= ~TP_STOP_QUEUE; + mb[2] |= (nv->bus[b].target[t].flags.enable_ppr << 5); + mb[3] = nv->bus[b].target[t].flags.sync_offset << 8; + mb[3] |= nv->bus[b].target[t].sync_period; + + mb[6] = nv->bus[b].target[t].flags.ppr_options << 8; + mb[6] |= nv->bus[b].target[t].flags.ppr_bus_width; + return( qla1280_mailbox_command(ha, BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]) ) ; +} + +STATIC void +qla12160_get_target_parameters(scsi_qla_host_t *ha, uint32_t b, uint32_t t, uint32_t l) +{ + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + mb[0] = MBC_GET_TARGET_PARAMETERS; + mb[1] = (uint16_t)(b ? t | BIT_7 :t); + mb[1] <<= 8; + qla1280_mailbox_command(ha, BIT_6|BIT_3|BIT_2|BIT_1|BIT_0, &mb[0]); + if( mb[3] != 0 ) + printk(KERN_INFO "scsi(%d:%d:%d:%d): Synchronous tranfer at period %d, offset %d. \n", + (int)ha->host_no, b, t, l, (mb[3] &0xff), (mb[3] >> 8)); + + if ( (mb[2] & BIT_5) && ((mb[6] >> 8) & 0xff) >= 2 ) + printk(KERN_INFO "scsi(%d:%d:%d:%d): Dual Transition enabled.\n", + (int)ha->host_no, b, t, l); +} + + +#ifdef QL_DEBUG_ROUTINES +/****************************************************************************/ +/* Driver Debug Functions. */ +/****************************************************************************/ + +/* + * Get byte from I/O port + */ +STATIC uint8_t +qla1280_getbyte(uint8_t *port) +{ + uint8_t ret; + +#if MEMORY_MAPPED_IO + ret = *port; +#else + ret = inb((int)port); +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_getbyte: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)ret, 16); + qla1280_print("\n\r"); + } + + return(ret); +} + +/* + * Get word from I/O port + */ +STATIC uint16_t +qla1280_getword(uint16_t *port) +{ + uint16_t ret; + +#if MEMORY_MAPPED_IO + ret = *port; +#else + ret = inw((int)port); +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_getword: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)ret, 16); + qla1280_print("\n\r"); + } + + return(ret); +} + +/* + * Get double word from I/O port + */ +STATIC uint32_t +qla1280_getdword(uint32_t *port) +{ + uint32_t ret; + +#if MEMORY_MAPPED_IO + ret = *port; +#else + ret = inl((int)port); +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_getdword: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)ret, 16); + qla1280_print("\n\r"); + } + + return(ret); +} + +/* + * Send byte to I/O port + */ +STATIC void +qla1280_putbyte(uint8_t *port, uint8_t data) +{ +#if MEMORY_MAPPED_IO + *port = data; +#else + outb(data, (int)port); +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_putbyte: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)data, 16); + qla1280_print("\n\r"); + } +} + +/* + * Send word to I/O port + */ +STATIC void +qla1280_putword(uint16_t *port, uint16_t data) +{ +#if MEMORY_MAPPED_IO + *port = data; +#else +#ifdef _LINUX_IOPORTS + outw(data, (int)port); +#else + outw((int)port, data); +#endif +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_putword: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)data, 16); + qla1280_print("\n\r"); + } +} + +/* + * Send double word to I/O port + */ +STATIC void +qla1280_putdword(uint32_t *port, uint32_t data) +{ +#if MEMORY_MAPPED_IO + *port = data; +#else +#ifdef _LINUX_IOPORTS + outl(data,(int)port); +#else + outl((int)port, data); +#endif +#endif + + if (ql_debug_print) + { + qla1280_print("qla1280_putdword: address = "); + qla1280_output_number((uint32_t)port, 16); + qla1280_print(" data = 0x"); + qla1280_output_number((uint32_t)data, 16); + qla1280_print("\n\r"); + } +} + +/* + * Dummy function to prevent warnings for + * declared and unused debug functions + */ +void +qla1280_debug(void) +{ + qla1280_getbyte(0); + qla1280_getword(0); + qla1280_getdword(0); + qla1280_putbyte(0, 0); + qla1280_putword(0, 0); + qla1280_putdword(0, 0); +} + +/* + * Out character to COM2 port. + * PORT must be at standard address for COM2 = 0x2F8, + * or COM1 = 0x3F8 + */ +#define OUTB(addr,data) outb((data),(addr)) + +STATIC void +qla1280_putc(uint8_t c) +{ +#ifdef QL_DEBUG_CONSOLE + printk("%c", c); +#else + int com_addr = 0x2f8; + int hardware_flow_control = 1; + int software_flow_control = 0; + uint8_t data; + + /* Wait for transmitter holding and shift registers for empty. */ + do + { + data = inb(com_addr+5); + }while (!(data & BIT_6)); + + /* + * Set BAUD rate for COM2 to 19200 (0x6) + */ + + /* Select rate divisor. */ + OUTB(com_addr+3, 0x83); + + /* BAUD rate divisor LSB. */ + OUTB(com_addr, 0xc); /* 0xC = 9600 baud */ + + /* BAUD rate divisor MSB. */ + OUTB(com_addr+1, 0); + + /* Set No parity, 8 bits, 1 stop bit and + select interrupt enable register. */ + OUTB(com_addr+3, 3); + + /* Disable interrupts. */ + OUTB(com_addr+1, 0); + + /* Set data terminal ready and request to send */ + OUTB(com_addr+4,3); + + if (hardware_flow_control) + { + /* Wait for clear-to-send and data-set-ready */ + do + { + data = inb(com_addr+6) & (BIT_5 + BIT_4); + }while (data != (BIT_5 + BIT_4)); + } + else if (software_flow_control) + { + /* Test for data ready. */ + data = inb(com_addr+5); + if (data & BIT_0) + { + /* If XOFF */ + data = inb(com_addr); + if (data == '\023') + { + /* Wait for XON */ + do + { + /* Wait for char */ + do + { + data = inb(com_addr+5); + }while (!(data & BIT_0)); + data = inb(com_addr); + }while (data != '\021'); + } + } + } + + /* Output character. */ + OUTB(com_addr, c); +#endif +} + +/* + * Out NULL terminated string to COM port. + */ +STATIC void +qla1280_print(caddr_t s) +{ + if (ql_debug_print) + { +#ifdef QL_DEBUG_CONSOLE + printk("%s",s); +#else + /* Output string. */ + while (*s) + qla1280_putc(*s++); +#endif + } +} + +/* + * Output long number to COM port. + */ +STATIC void +qla1280_output_number(uint32_t n, uint8_t base) +{ + int8_t str[12]; + int8_t *s = &str[11]; + int8_t output = 0; + int8_t hex = FALSE; + + if (ql_debug_print) + { + if (base == 10 || base == 16) + { + if (base == 16 && n > 9) + hex = TRUE; + + *s = 0; + do + { + s--; + *s = n % base; + if (*s > 9) + *s += 55; + else + *s += '0'; + n /= base; + }while (n); + + for (; *s; s++) + { + if (*s != '0') + output = 1; + if (output) + qla1280_putc(*s); + } + if (!output) + qla1280_putc(*--s); + + if (hex) + qla1280_putc('h'); + } + } +} + +STATIC void +qla1280_dump_buffer(caddr_t b, uint32_t size) +{ + uint32_t cnt; + uint8_t c; + + if (ql_debug_print) + { + qla1280_print( + " 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh Fh\n\r"); + qla1280_print( + "---------------------------------------------------------------\n\r"); + + for (cnt = 0; cnt < size; ) + { + c = *b++; + if (c < 16) + qla1280_putc(' '); + qla1280_output_number((uint32_t)c, 16); + cnt++; + if (!(cnt % 16)) + qla1280_print("\n\r"); + else if (c < 10) + qla1280_print(" "); + else + qla1280_putc(' '); + } + if (cnt % 16) + qla1280_print("\n\r"); + } +} +/************************************************************************** + * ql1280_print_scsi_cmd + * + **************************************************************************/ +void qla1280_print_scsi_cmd(Scsi_Cmnd *cmd) +{ + scsi_qla_host_t *ha; + struct Scsi_Host *host = cmd->host; + srb_t *sp; + /* struct scatterlist *sg; */ + + int i; + ha = (scsi_qla_host_t *) host->hostdata; + + ql_debug_print = 1; + sp = (srb_t *) CMD_SP(cmd); + sprintf(debug_buff,"SCSI Command @= 0x%p, Handle=0x%p\n\r", cmd, CMD_HANDLE(cmd)); + qla1280_print(debug_buff); + sprintf(debug_buff," chan=%d, target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n\r", + cmd->channel, cmd->target, cmd->lun, cmd->cmd_len); + qla1280_print(debug_buff); + qla1280_print(" CDB = "); + for (i = 0; i < cmd->cmd_len; i++) + { + sprintf(debug_buff,"0x%02x ", cmd->cmnd[i]); + qla1280_print(debug_buff); + } + sprintf(debug_buff," seg_cnt =%d\n\r",cmd->use_sg); + qla1280_print(debug_buff); + sprintf(debug_buff," request buffer=0x%p, request buffer len=0x%x\n\r",cmd->request_buffer,cmd->request_bufflen); + qla1280_print(debug_buff); + /* if( cmd->use_sg ) + { + sg = (struct scatterlist *) cmd->request_buffer; + qla1280_print(" SG buffer: \n\r"); + qla1280_dump_buffer((caddr_t)sg, (cmd->use_sg*sizeof(struct scatterlist)) ); + } */ + sprintf(debug_buff," tag=%d, flags=0x%x, transfersize=0x%x \n\r", + cmd->tag, cmd->flags,cmd->transfersize ); + qla1280_print(debug_buff); + sprintf(debug_buff," Pid=%d, SP=0x%p\n\r", (int)cmd->pid, CMD_SP(cmd)); + qla1280_print(debug_buff); + sprintf(debug_buff," r_start=0x%lx, u_start=0x%lx\n\r",sp->r_start,sp->u_start); + qla1280_print(debug_buff); + sprintf(debug_buff," underflow size = 0x%x, direction=0x%x, req.cmd=0x%x \n\r", cmd->underflow, sp->dir,cmd->request.cmd); + qla1280_print(debug_buff); +} +/************************************************************************** + * ql1280_dump_device + * + **************************************************************************/ +void +ql1280_dump_device(scsi_qla_host_t *ha) +{ + + Scsi_Cmnd *cp; + srb_t *sp; + int i; + qla1280_print("Outstanding Commands on controller:\n\r"); + for ( i=0; i < MAX_OUTSTANDING_COMMANDS; i++ ) + { + if( (sp = ha->outstanding_cmds[i]) == NULL ) + continue; + if( (cp = sp->cmd) == NULL ) + continue; + qla1280_print_scsi_cmd(cp); + } + +} +#endif + +#ifdef QLA1280_UNUSED +/************************************************************************** + * ql1280_dump_regs + * + **************************************************************************/ +static void qla1280_dump_regs(struct Scsi_Host *host) +{ + printk("Mailbox registers:\n"); + printk("qla1280 : mbox 0 0x%04x \n", inw(host->io_port + 0x70)); + printk("qla1280 : mbox 1 0x%04x \n", inw(host->io_port + 0x72)); + printk("qla1280 : mbox 2 0x%04x \n", inw(host->io_port + 0x74)); + printk("qla1280 : mbox 3 0x%04x \n", inw(host->io_port + 0x76)); + printk("qla1280 : mbox 4 0x%04x \n", inw(host->io_port + 0x78)); + printk("qla1280 : mbox 5 0x%04x \n", inw(host->io_port + 0x7a)); +} +#endif + + + +#if STOP_ON_ERROR +/************************************************************************** + * ql1280_panic + * + **************************************************************************/ +static void qla1280_panic(char *cp, struct Scsi_Host *host) +{ + scsi_qla_host_t *ha; + long *fp; + + ha = (scsi_qla_host_t *) host->hostdata; + printk("qla1280 - PANIC: %s\n",cp); + printk("Current time=0x%lx\n", jiffies); + printk("Number of pending commands =0x%lx\n", ha->actthreads); + printk("Number of SCSI queued commands =0x%lx\n", ha->qthreads); + printk("Number of free entries = (%d)\n",ha->req_q_cnt); + printk("Request Queue @ 0x%lx, Response Queue @ 0x%lx\n", + ha->request_dma, + ha->response_dma); + printk("Request In Ptr %d\n", ha->req_ring_index ); + fp = (long *) &ha->flags; + printk("HA flags =0x%lx\n", *fp); + DEBUG2(ql_debug_print = 1;) + /* DEBUG2(ql1280_dump_device((scsi_qla_host_t *) host->hostdata)); */ +#ifdef QLA1280_UNUSED + qla1280_dump_regs(host); +#endif + sti(); + panic("Ooops"); + /* cli(); + for(;;) + { + barrier(); + sti(); + } + */ +} +#endif + +#ifdef QLA1280_UNUSED +static void qla1280_set_flags(char * s) +{ +} +#endif + +/************************************************************************** + * qla1280_setup + * + * Handle Linux boot parameters. This routine allows for assigning a value + * to a parameter with a ':' between the parameter and the value. + * ie. qla1280=max_reqs:0x0A,verbose + **************************************************************************/ +void +qla1280_setup(char *s, int *dummy) +{ + char *end, *str, *cp; + +#ifdef QLA1280_UNUSED + static struct + { + const char *name; + int siz; + void (*func)(); + int arg; + } options[] = + { + { "dump_regs", 9, &qla1280_dump_regs, 0 + }, + { "verbose", 7, &qla1280_set_flags, 0x1 + }, + { "", 0, NULL, 0 + } + }; +#endif + + printk("scsi: Processing Option str = %s\n", s); + end = strchr(s, '\0'); + /* locate command */ + str = s; + for( cp = s; *cp && cp != end; cp++ ) + { + cp = qla1280_get_token(cp, str); + printk("scsi: token str = %s\n", str); + /* if found execute routine */ + + } + +} + +static char *qla1280_get_token(char *cmdline, char *str ) +{ + register char *cp = cmdline; + + /* skip preceeding spaces */ + while(strchr(cp,' ')) + ++cp; + /* symbol starts here */ + str = cp; + /* skip char if not a space or : */ + while (*cp && !( strchr(cp,' ') || strchr(cp,':')) ) + cp++; + *cp = '\0'; + return( cp ); +} + +/* + * Overrides for Emacs so that we almost follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 2 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ + diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/qla1280.h linux/drivers/scsi/qla1280.h --- v2.3.42/linux/drivers/scsi/qla1280.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/qla1280.h Wed Feb 9 21:34:55 2000 @@ -0,0 +1,1737 @@ +/************************************************************************* + * QLOGIC LINUX SOFTWARE + * + * QLogic ISP1x80/1x160 device driver for Linux 2.3.x (redhat 6.x). + * + * COPYRIGHT (C) 1996-2000 QLOGIC CORPORATION + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Qlogic's Linux Software License. + * + * This program is WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistribution's or source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + *****************************************************************************/ + +/************************************************************************************* + QLOGIC CORPORATION SOFTWARE + "GNU" GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION + AND MODIFICATION + +This GNU General Public License ("License") applies solely to QLogic Linux +Software ("Software") and may be distributed under the terms of this License. + +1. You may copy and distribute verbatim copies of the Software's source code as +you receive it, in any medium, provided that you conspicuously and appropriately +publish on each copy an appropriate copyright notice and disclaimer of warranty; +keep intact all the notices that refer to this License and to the absence of any +warranty; and give any other recipients of the Software a copy of this License along +with the Software. + +You may charge a fee for the physical act of transferring a copy, and you may at your +option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Software or any portion of it, thus forming +a work based on the Software, and copy and distribute such modifications or work under +the terms of Section 1 above, provided that you also meet all of these conditions: + +* a) You must cause the modified files to carry prominent notices stating that you +changed the files and the date of any change. + +* b) You must cause any work that you distribute or publish that in whole or in part +contains or is derived from the Software or any part thereof, to be licensed as a +whole at no charge to all third parties under the terms of this License. + +* c) If the modified Software normally reads commands interactively when run, you +must cause it, when started running for such interactive use in the most ordinary way, +to print or display an announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide a warranty) and that +users may redistribute the Software under these conditions, and telling the user how to +view a copy of this License. (Exception:if the Software itself is interactive but does +not normally print such an announcement, your work based on the Software is not required +to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable sections of +that work are not derived from the Software, and can be reasonably considered independent +and separate works in themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you distribute the same +sections as part of a whole which is a work based on the Software, the distribution of the +whole must be on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote it. + +3. You may copy and distribute the Software (or a work based on it, under Section 2) in +object code or executable form under the terms of Sections 1 and 2 above provided that +you also do one of the following: + +* a) Accompany it with the complete corresponding machine-readable source code, which must +be distributed under the terms of Sections 1 and 2 above on a medium customarily used for +software interchange; or, + +* b) Accompany it with a written offer, valid for at least three years, to give any third +party, for a charge no more than your cost of physically performing source distribution, +a complete machine-readable copy of the corresponding source code, to be distributed under +the terms of Sections 1 and 2 above on a medium customarily used for software interchange; +or, + +* c) Accompany it with the information you received as to the offer to distribute +corresponding source code. (This alternative is allowed only for noncommercial distribution +and only if you received the Software in object code or executable form with such an offer, +in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications +to it. For an executable work, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus the scripts used +to control compilation and installation of the executable. + +If distribution of executable or object code is made by offering access to copy from a +designated place, then offering equivalent access to copy the source code from the same +place counts as distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Software except as expressly +provided under this License. Any attempt otherwise to copy, modify, sublicense or +distribute the Software is void, and will automatically terminate your rights under this +License. However, parties who have received copies, or rights, from you under this License +will not have their licenses terminated so long as such parties remain in full compliance. + +5. This license grants you world wide, royalty free non-exclusive rights to modify or +distribute the Software or its derivative works. These actions are prohibited by law +if you do not accept this License. Therefore, by modifying or distributing the Software +(or any work based on the Software), you indicate your acceptance of this License to do +so, and all its terms and conditions for copying, distributing or modifying the Software +or works based on it. + +6. Each time you redistribute the Software (or any work based on the Software), the +recipient automatically receives a license from the original licensor to copy, distribute +or modify the Software subject to these terms and conditions. You may not impose any +further restrictions on the recipients' exercise of the rights granted herein. You are +not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for +any other reason (not limited to patent issues), conditions are imposed on you +(whether by court order, agreement or otherwise) that contradict the conditions of this +License, they do not excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this License +and any other pertinent obligations, then as a consequence you may not distribute the +Software at all. + +If any portion of this section is held invalid or unenforceable under any particular +circumstance, the balance of the section is intended to apply and the section as a whole +is intended to apply in other circumstances. +NO WARRANTY + +11. THE SOFTWARE IS PROVIDED WITHOUT A WARRANTY OF ANY KIND. THERE IS NO +WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. +SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE SOFTWARE AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING +BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO +OPERATE WITH ANY OTHER SOFTWARES), EVEN IF SUCH HOLDER OR OTHER PARTY HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +*************************************************************************************/ + + +#ifndef _IO_HBA_QLA1280_H /* wrapper symbol for kernel use */ +#define _IO_HBA_QLA1280_H /* subject to change without notice */ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +/* + * Enable define statement to ignore Data Underrun Errors, + * remove define statement to enable detection. + */ +/* #define DATA_UNDERRUN_ERROR_DISABLE */ + +/* + * Driver debug definitions. + */ +/* #define QL_DEBUG_LEVEL_1 */ /* Output register accesses to COM2. */ +/* #define QL_DEBUG_LEVEL_2 */ /* Output error msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_3 */ /* Output function trace msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_4 */ /* Output NVRAM trace msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_5 */ /* Output ring trace msgs to COM2. */ +/* #define QL_DEBUG_LEVEL_6 */ /* Output WATCHDOG timer trace to COM2. */ +/* #define QL_DEBUG_LEVEL_7 */ /* Output RISC load trace msgs to COM2. */ + +#define QL_DEBUG_CONSOLE /* Output to console instead of COM2. */ + +#ifndef TRUE +# define TRUE 1 +#endif +#ifndef FALSE +# define FALSE 0 +#endif + + +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) +# if defined(__sparc_v9__) || defined(__powerpc__) +# error "PPC and Sparc platforms are only support under 2.1.92 and above" +# endif +#endif + + +/* + * Locking + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) +# include +# include +# define cpuid smp_processor_id() +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +# define DRIVER_LOCK_INIT \ + spin_lock_init(&ha->spin_lock); +# define DRIVER_LOCK \ + if(!ha->cpu_lock_count[cpuid]) { \ + spin_lock_irqsave(&ha->spin_lock, cpu_flags); \ + ha->cpu_lock_count[cpuid]++; \ + } else { \ + ha->cpu_lock_count[cpuid]++; \ + } +# define DRIVER_UNLOCK \ + if(--ha->cpu_lock_count[cpuid] == 0) \ + spin_unlock_irqrestore(&ha->spin_lock, cpu_flags); +# else +# define DRIVER_LOCK_INIT +# define DRIVER_LOCK +# define DRIVER_UNLOCK +# endif +#else +# define cpuid 0 +# define DRIVER_LOCK_INIT +# define DRIVER_LOCK \ + save_flags(cpu_flags); \ + cli(); +# define DRIVER_UNLOCK \ + restore_flags(cpu_flags); +# define le32_to_cpu(x) (x) +# define cpu_to_le32(x) (x) +#endif + +/* + * Data bit definitions. + */ +#define BIT_0 0x1 +#define BIT_1 0x2 +#define BIT_2 0x4 +#define BIT_3 0x8 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x100 +#define BIT_9 0x200 +#define BIT_10 0x400 +#define BIT_11 0x800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_16 0x10000 +#define BIT_17 0x20000 +#define BIT_18 0x40000 +#define BIT_19 0x80000 +#define BIT_20 0x100000 +#define BIT_21 0x200000 +#define BIT_22 0x400000 +#define BIT_23 0x800000 +#define BIT_24 0x1000000 +#define BIT_25 0x2000000 +#define BIT_26 0x4000000 +#define BIT_27 0x8000000 +#define BIT_28 0x10000000 +#define BIT_29 0x20000000 +#define BIT_30 0x40000000 +#define BIT_31 0x80000000 + +/* + * Common size type definitions + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +#endif + +/* + * Local Macro Definitions. + */ +#if defined(QL_DEBUG_LEVEL_1) || defined(QL_DEBUG_LEVEL_2) || \ + defined(QL_DEBUG_LEVEL_3) || defined(QL_DEBUG_LEVEL_4) || \ + defined(QL_DEBUG_LEVEL_5) || defined(QL_DEBUG_LEVEL_6) || \ + defined(QL_DEBUG_LEVEL_7) + #define QL_DEBUG_ROUTINES +#endif + +/* + * I/O port macros +*/ +#define LINUX_IOPORTS /* Linux in/out routines are define*/ + /* differently from other OSs */ +/* #define MEMORY_MAPPED_IO */ /* Enable memory mapped I/O */ +#undef MEMORY_MAPPED_IO /* Disable memory mapped I/O */ + +#ifdef QL_DEBUG_LEVEL_1 +#define RD_REG_BYTE(addr) qla1280_getbyte((uint8_t *)addr) +#define RD_REG_WORD(addr) qla1280_getword((uint16_t *)addr) +#define RD_REG_DWORD(addr) qla1280_getdword((uint32_t *)addr) +#define WRT_REG_BYTE(addr, data) qla1280_putbyte((uint8_t *)addr, data) +#define WRT_REG_WORD(addr, data) qla1280_putword((uint16_t *)addr, data) +#define WRT_REG_DWORD(addr, data) qla1280_putdword((uint32_t *)addr, data) +#else /* QL_DEBUG_LEVEL_1 */ +#ifdef MEMORY_MAPPED_IO + #define RD_REG_BYTE(addr) readb((unsigned long) (addr) + #define RD_REG_WORD(addr) readw((unsigned long) (addr) + #define RD_REG_DWORD(addr) readl((unsigned long) (addr) + #define WRT_REG_BYTE(addr, data) writeb((data), (unsigned long) (addr)) + #define WRT_REG_WORD(addr, data) writew((data), (unsigned long) (addr)) + #define WRT_REG_DWORD(addr, data) writel((data), (unsigned long) (addr)) +#else /* MEMORY_MAPPED_IO */ +#define RD_REG_BYTE(addr) (inb((unsigned long)addr)) +#define RD_REG_WORD(addr) (inw((unsigned long)addr)) +#define RD_REG_DWORD(addr) (inl((unsigned long)addr)) +#ifdef LINUX_IOPORTS +/* Parameters are reversed in Linux */ +#define WRT_REG_BYTE(addr, data) (outb(data,(unsigned long)addr)) +#define WRT_REG_WORD(addr, data) (outw(data,(unsigned long)addr)) +#define WRT_REG_DWORD(addr, data) (outl(data,(unsigned long)addr)) +#else +#define WRT_REG_BYTE(addr, data) (outb((unsigned long)addr, data)) +#define WRT_REG_WORD(addr, data) (outw((unsigned long)addr, data)) +#define WRT_REG_DWORD(addr, data) (outl((unsigned long)addr, data)) +#endif +#endif /* MEMORY_MAPPED_IO */ +#endif /* QL_DEBUG_LEVEL_1 */ + +/* + * Host adapter default definitions. + */ +#define MAX_BUSES 2 /* 2 */ +#define MAX_B_BITS 1 + +#define MAX_TARGETS 16 /* 16 */ +#define MAX_T_BITS 4 /* 4 */ + +#define MAX_LUNS 8 /* 32 */ +#define MAX_L_BITS 3 /* 5 */ + +/* + * Watchdog time quantum + */ +#define QLA1280_WDG_TIME_QUANTUM 5 /* In seconds */ + +/* Command retry count (0-65535) */ +#define COMMAND_RETRY_COUNT 255 + +/* Maximum outstanding commands in ISP queues (1-65535) */ +#define MAX_OUTSTANDING_COMMANDS 512 + +/* ISP request and response entry counts (37-65535) */ +#define REQUEST_ENTRY_CNT 256 /* Number of request entries. */ +#define RESPONSE_ENTRY_CNT 16 /* Number of response entries. */ + +/* Maximum equipage per controller */ +#define MAX_EQ (MAX_BUSES * MAX_TARGETS * MAX_LUNS) + +/* Number of segments 1 - 65535 */ +#define SG_SEGMENTS 32 /* Cmd entry + 6 continuations */ + + +typedef struct timer_list timer_t; /* timer */ + +/* + * SCSI Request Block structure + */ +typedef struct srb +{ + Scsi_Cmnd *cmd; /* (4) SCSI command block */ + struct srb *s_next; /* (4) Next block on LU queue */ + struct srb *s_prev; /* (4) Previous block on LU queue */ + uint8_t flags; /* (1) Status flags. */ + uint8_t dir; /* direction of transfer */ + uint8_t unused[2]; + u_long r_start; /* jiffies at start of request */ + u_long u_start; /* jiffies when sent to F/W */ +}srb_t; + +/* + * SRB flag definitions + */ +#define SRB_TIMEOUT BIT_0 /* Command timed out */ +#define SRB_SENT BIT_1 /* Command sent to ISP */ +#define SRB_ABORT_PENDING BIT_2 /* Command abort sent to device */ +#define SRB_ABORTED BIT_3 /* Command aborted command already */ + + +/* + * Logical Unit Queue structure + */ +typedef struct scsi_lu +{ + srb_t *q_first; /* First block on LU queue */ + srb_t *q_last; /* Last block on LU queue */ + uint8_t q_flag; /* LU queue state flags */ + uint8_t q_sense[16]; /* sense data */ + u_long io_cnt; /* total xfer count */ + u_long resp_time; /* total response time (start - finish) */ + u_long act_time; /* total actived time (minus queuing time) */ + u_long w_cnt; /* total writes */ + u_long r_cnt; /* total reads */ + uint16_t q_outcnt; /* Pending jobs for this LU */ +#if QL1280_TARGET_MODE_SUPPORT + void (*q_func)(); /* Target driver event handler */ + int32_t q_param; /* Target driver event param */ + uint8_t q_lock; /* Device Queue Lock */ +#endif +}scsi_lu_t; + +/* + * Logical Unit flags + */ +#define QLA1280_QBUSY BIT_0 +#define QLA1280_QWAIT BIT_1 +#define QLA1280_QSUSP BIT_2 +#define QLA1280_QSENSE BIT_3 /* Sense data cache valid */ +#define QLA1280_QRESET BIT_4 +#define QLA1280_QHBA BIT_5 +#define QLA1280_BSUSP BIT_6 /* controller is suspended */ +#define QLA1280_BREM BIT_7 /* controller is removed */ + +/* + * ISP PCI Configuration Register Set + */ +typedef volatile struct +{ + uint16_t vendor_id; /* 0x0 */ + uint16_t device_id; /* 0x2 */ + uint16_t command; /* 0x4 */ + uint16_t status; /* 0x6 */ + uint8_t revision_id; /* 0x8 */ + uint8_t programming_interface; /* 0x9 */ + uint8_t sub_class; /* 0xa */ + uint8_t base_class; /* 0xb */ + uint8_t cache_line; /* 0xc */ + uint8_t latency_timer; /* 0xd */ + uint8_t header_type; /* 0xe */ + uint8_t bist; /* 0xf */ + uint32_t base_port; /* 0x10 */ + uint32_t mem_base_addr; /* 0x14 */ + uint32_t base_addr[4]; /* 0x18-0x24 */ + uint32_t reserved_1[2]; /* 0x28-0x2c */ + uint16_t expansion_rom; /* 0x30 */ + uint32_t reserved_2[2]; /* 0x34-0x38 */ + uint8_t interrupt_line; /* 0x3c */ + uint8_t interrupt_pin; /* 0x3d */ + uint8_t min_grant; /* 0x3e */ + uint8_t max_latency; /* 0x3f */ +}config_reg_t; + +/* + * ISP I/O Register Set structure definitions. + */ +typedef volatile struct +{ + uint16_t id_l; /* ID low */ + uint16_t id_h; /* ID high */ + uint16_t cfg_0; /* Configuration 0 */ + uint16_t cfg_1; /* Configuration 1 */ + uint16_t ictrl; /* Interface control */ + #define ISP_RESET BIT_0 /* ISP soft reset */ + #define ISP_EN_INT BIT_1 /* ISP enable interrupts. */ + #define ISP_EN_RISC BIT_2 /* ISP enable RISC interrupts. */ + uint16_t istatus; /* Interface status */ + #define PCI_64BIT_SLOT BIT_14 /* PCI 64-bit slot indicator. */ + #define RISC_INT BIT_2 /* RISC interrupt */ + #define PCI_INT BIT_1 /* PCI interrupt */ + uint16_t semaphore; /* Semaphore */ + uint16_t nvram; /* NVRAM register. */ + #define NV_DESELECT 0 + #define NV_CLOCK BIT_0 + #define NV_SELECT BIT_1 + #define NV_DATA_OUT BIT_2 + #define NV_DATA_IN BIT_3 + uint16_t flash_data; /* Flash BIOS data */ + uint16_t flash_address; /* Flash BIOS address */ + + uint16_t unused_1[0x2e]; /* 0x14-0x6f Gap */ + + uint16_t mailbox0; /* Mailbox 0 */ + uint16_t mailbox1; /* Mailbox 1 */ + uint16_t mailbox2; /* Mailbox 2 */ + uint16_t mailbox3; /* Mailbox 3 */ + uint16_t mailbox4; /* Mailbox 4 */ + uint16_t mailbox5; /* Mailbox 5 */ + uint16_t mailbox6; /* Mailbox 6 */ + uint16_t mailbox7; /* Mailbox 7 */ + + uint16_t unused_2[0x20]; /* 0x80-0xbf Gap */ + + uint16_t host_cmd; /* Host command and control */ + #define HOST_INT BIT_7 /* host interrupt bit */ + #define BIOS_ENABLE BIT_0 + + uint16_t unused_6[0x5]; /* 0xc2-0xcb Gap */ + + uint16_t gpio_data; + uint16_t gpio_enable; + + uint16_t unused_7[0x11]; /* d0-f0 */ + uint16_t scsiControlPins; /* f2 */ + +}device_reg_t; + +#define MAILBOX_REGISTER_COUNT 8 + +/* + * ISP product identification definitions in mailboxes after reset. + */ +#define PROD_ID_1 0x4953 +#define PROD_ID_2 0x0000 +#define PROD_ID_2a 0x5020 +#define PROD_ID_3 0x2020 +#define PROD_ID_4 0x1 + +/* + * ISP host command and control register command definitions + */ +#define HC_RESET_RISC 0x1000 /* Reset RISC */ +#define HC_PAUSE_RISC 0x2000 /* Pause RISC */ +#define HC_RELEASE_RISC 0x3000 /* Release RISC from reset. */ +#define HC_SET_HOST_INT 0x5000 /* Set host interrupt */ +#define HC_CLR_HOST_INT 0x6000 /* Clear HOST interrupt */ +#define HC_CLR_RISC_INT 0x7000 /* Clear RISC interrupt */ +#define HC_DISABLE_BIOS 0x9000 /* Disable BIOS. */ + +/* + * ISP mailbox Self-Test status codes + */ +#define MBS_FRM_ALIVE 0 /* Firmware Alive. */ +#define MBS_CHKSUM_ERR 1 /* Checksum Error. */ +#define MBS_SHADOW_LD_ERR 2 /* Shadow Load Error. */ +#define MBS_BUSY 4 /* Busy. */ + +/* + * ISP mailbox command complete status codes + */ +#define MBS_CMD_CMP 0x4000 /* Command Complete. */ +#define MBS_INV_CMD 0x4001 /* Invalid Command. */ +#define MBS_HOST_INF_ERR 0x4002 /* Host Interface Error. */ +#define MBS_TEST_FAILED 0x4003 /* Test Failed. */ +#define MBS_CMD_ERR 0x4005 /* Command Error. */ +#define MBS_CMD_PARAM_ERR 0x4006 /* Command Parameter Error. */ + +/* + * ISP mailbox asynchronous event status codes + */ +#define MBA_ASYNC_EVENT 0x8000 /* Asynchronous event. */ +#define MBA_BUS_RESET 0x8001 /* SCSI Bus Reset. */ +#define MBA_SYSTEM_ERR 0x8002 /* System Error. */ +#define MBA_REQ_TRANSFER_ERR 0x8003 /* Request Transfer Error. */ +#define MBA_RSP_TRANSFER_ERR 0x8004 /* Response Transfer Error. */ +#define MBA_WAKEUP_THRES 0x8005 /* Request Queue Wake-up. */ +#define MBA_TIMEOUT_RESET 0x8006 /* Execution Timeout Reset. */ +#define MBA_DEVICE_RESET 0x8007 /* Bus Device Reset. */ +#define MBA_BUS_MODE_CHANGE 0x800E /* SCSI bus mode transition. */ +#define MBA_SCSI_COMPLETION 0x8020 /* Completion response. */ + +/* + * ISP mailbox commands + */ +#define MBC_NOP 0 /* No Operation. */ +#define MBC_LOAD_RAM 1 /* Load RAM. */ +#define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */ +#define MBC_WRITE_RAM_WORD 4 /* Write ram word. */ +#define MBC_READ_RAM_WORD 5 /* Read ram word. */ +#define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ +#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */ +#define MBC_ABOUT_FIRMWARE 8 /* Get firmware revision. */ +#define MBC_INIT_REQUEST_QUEUE 0x10 /* Initialize request queue. */ +#define MBC_INIT_RESPONSE_QUEUE 0x11 /* Initialize response queue. */ +#define MBC_EXECUTE_IOCB 0x12 /* Execute IOCB command. */ +#define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */ +#define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */ +#define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */ +#define MBC_BUS_RESET 0x18 /* SCSI bus reset. */ +#define MBC_GET_RETRY_COUNT 0x22 /* Get retry count and delay. */ +#define MBC_GET_TARGET_PARAMETERS 0x28 /* Get target parameters. */ +#define MBC_SET_INITIATOR_ID 0x30 /* Set initiator SCSI ID. */ +#define MBC_SET_SELECTION_TIMEOUT 0x31 /* Set selection timeout. */ +#define MBC_SET_RETRY_COUNT 0x32 /* Set retry count and delay. */ +#define MBC_SET_TAG_AGE_LIMIT 0x33 /* Set tag age limit. */ +#define MBC_SET_CLOCK_RATE 0x34 /* Set clock rate. */ +#define MBC_SET_ACTIVE_NEGATION 0x35 /* Set active negation state. */ +#define MBC_SET_ASYNC_DATA_SETUP 0x36 /* Set async data setup time. */ +#define MBC_SET_PCI_CONTROL 0x37 /* Set BUS control parameters. */ +#define MBC_SET_TARGET_PARAMETERS 0x38 /* Set target parameters. */ +#define MBC_SET_DEVICE_QUEUE 0x39 /* Set device queue parameters */ +#define MBC_SET_SYSTEM_PARAMETER 0x45 /* Set system parameter word. */ +#define MBC_SET_FIRMWARE_FEATURES 0x4A /* Set firmware feature word. */ +#define MBC_INIT_REQUEST_QUEUE_A64 0x52 /* Initialize request queue A64 */ +#define MBC_INIT_RESPONSE_QUEUE_A64 0x53 /* Initialize response q A64. */ +#define MBC_ENABLE_TARGET_MODE 0x55 /* Enable target mode. */ + +/* + * ISP Get/Set Target Parameters mailbox command control flags. + */ +#define TP_RENEGOTIATE BIT_8 /* Renegotiate on error. */ +#define TP_STOP_QUEUE BIT_9 /* Stop que on check condition */ +#define TP_AUTO_REQUEST_SENSE BIT_10 /* Automatic request sense. */ +#define TP_TAGGED_QUEUE BIT_11 /* Tagged queuing. */ +#define TP_SYNC BIT_12 /* Synchronous data transfers. */ +#define TP_WIDE BIT_13 /* Wide data transfers. */ +#define TP_PARITY BIT_14 /* Parity checking. */ +#define TP_DISCONNECT BIT_15 /* Disconnect privilege. */ + +/* + * NVRAM Command values. + */ +#define NV_START_BIT BIT_2 +#define NV_WRITE_OP (BIT_26+BIT_24) +#define NV_READ_OP (BIT_26+BIT_25) +#define NV_ERASE_OP (BIT_26+BIT_25+BIT_24) +#define NV_MASK_OP (BIT_26+BIT_25+BIT_24) +#define NV_DELAY_COUNT 10 + +/* + * QLogic ISP1280 NVRAM structure definition. + */ +typedef struct +{ + uint8_t id[4]; /* 0, 1, 2, 3 */ + uint8_t version; /* 4 */ + + struct + { + uint8_t bios_configuration_mode :2; + uint8_t bios_disable :1; + uint8_t selectable_scsi_boot_enable :1; + uint8_t cd_rom_boot_enable :1; + uint8_t disable_loading_risc_code :1; + uint8_t enable_64bit_addressing :1; + uint8_t unused_7 :1; + }cntr_flags_1; /* 5 */ + + struct + { + uint8_t boot_lun_number :5; + uint8_t scsi_bus_number :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + uint8_t boot_target_number :4; + uint8_t unused_12 :1; + uint8_t unused_13 :1; + uint8_t unused_14 :1; + uint8_t unused_15 :1; + }cntr_flags_2; /* 6, 7 */ + + uint16_t unused_8; /* 8, 9 */ + uint16_t unused_10; /* 10, 11 */ + uint16_t unused_12; /* 12, 13 */ + uint16_t unused_14; /* 14, 15 */ + + union + { + uint8_t c; + struct + { + uint8_t reserved :2; + uint8_t burst_enable :1; + uint8_t reserved_1 :1; + uint8_t fifo_threshold :4; + }f; + }isp_config; /* 16 */ + + /* Termination + * 0 = Disable, 1 = high only, 3 = Auto term + */ + union + { + uint8_t c; + struct + { + uint8_t scsi_bus_1_control :2; + uint8_t scsi_bus_0_control :2; + uint8_t unused_0 :1; + uint8_t unused_1 :1; + uint8_t unused_2 :1; + uint8_t auto_term_support :1; + }f; + }termination; /* 17 */ + + uint16_t isp_parameter; /* 18, 19 */ + + union + { + uint16_t w; + struct + { + uint8_t enable_fast_posting :1; + uint8_t report_lvd_bus_transition :1; + uint8_t unused_2 :1; + uint8_t unused_3 :1; + uint8_t unused_4 :1; + uint8_t unused_5 :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + uint8_t unused_8 :1; + uint8_t unused_9 :1; + uint8_t unused_10 :1; + uint8_t unused_11 :1; + uint8_t unused_12 :1; + uint8_t unused_13 :1; + uint8_t unused_14 :1; + uint8_t unused_15 :1; + }f; + }firmware_feature; /* 20, 21 */ + + uint16_t unused_22; /* 22, 23 */ + + struct + { + struct + { + uint8_t initiator_id :4; + uint8_t scsi_reset_disable :1; + uint8_t scsi_bus_size :1; + uint8_t scsi_bus_type :1; + uint8_t unused_7 :1; + }config_1; /* 24 */ + + uint8_t bus_reset_delay; /* 25 */ + uint8_t retry_count; /* 26 */ + uint8_t retry_delay; /* 27 */ + + struct + { + uint8_t async_data_setup_time :4; + uint8_t req_ack_active_negation :1; + uint8_t data_line_active_negation :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + }config_2; /* 28 */ + + uint8_t unused_29; /* 29 */ + + uint16_t selection_timeout; /* 30, 31 */ + uint16_t max_queue_depth; /* 32, 33 */ + + uint16_t unused_34; /* 34, 35 */ + uint16_t unused_36; /* 36, 37 */ + uint16_t unused_38; /* 38, 39 */ + + struct + { + union + { + uint8_t c; + struct + { + uint8_t renegotiate_on_error :1; + uint8_t stop_queue_on_check :1; + uint8_t auto_request_sense :1; + uint8_t tag_queuing :1; + uint8_t sync_data_transfers :1; + uint8_t wide_data_transfers :1; + uint8_t parity_checking :1; + uint8_t disconnect_allowed :1; + }f; + }parameter; /* 40 */ + + uint8_t execution_throttle; /* 41 */ + uint8_t sync_period; /* 42 */ + + struct + { + uint8_t sync_offset :4; + uint8_t device_enable :1; + uint8_t lun_disable :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + }flags; /* 43 */ + + uint16_t unused_44; /* 44, 45 */ + }target[MAX_TARGETS]; + }bus[MAX_BUSES]; + + uint16_t unused_248; /* 248, 249 */ + + uint16_t subsystem_id[2]; /* 250, 251, 252, 253 */ + + uint8_t unused_254; /* 254 */ + + uint8_t chksum; /* 255 */ +}nvram_t; + +/* + * QLogic ISP12160 NVRAM structure definition. + */ +typedef struct +{ + uint8_t id[4]; /* 0, 1, 2, 3 */ + uint8_t version; /* 4 */ + /* Host/Bios Flags */ + struct + { + uint8_t bios_configuration_mode :2; + uint8_t bios_disable :1; + uint8_t selectable_scsi_boot_enable :1; + uint8_t cd_rom_boot_enable :1; + uint8_t disable_loading_risc_code :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + }cntr_flags_1; /* 5 */ + /* Selectable Boot Support */ + struct + { + uint8_t boot_lun_number :5; + uint8_t scsi_bus_number :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + uint8_t boot_target_number :4; + uint8_t unused_12 :1; + uint8_t unused_13 :1; + uint8_t unused_14 :1; + uint8_t unused_15 :1; + }cntr_flags_2; /* 6, 7 */ + + uint16_t unused_8; /* 8, 9 */ + uint16_t unused_10; /* 10, 11 */ + uint16_t unused_12; /* 12, 13 */ + uint16_t unused_14; /* 14, 15 */ + + /* ISP Config Parameters */ + union + { + uint8_t c; + struct + { + uint8_t reserved :2; + uint8_t burst_enable :1; + uint8_t reserved_1 :1; + uint8_t fifo_threshold :4; + }f; + }isp_config; /* 16 */ + + /* Termination + * 0 = Disable, 1 = high only, 3 = Auto term + */ + union + { + uint8_t c; + struct + { + uint8_t scsi_bus_1_control :2; + uint8_t scsi_bus_0_control :2; + uint8_t unused_0 :1; + uint8_t unused_1 :1; + uint8_t unused_2 :1; + uint8_t auto_term_support :1; + }f; + }termination; /* 17 */ + /* Auto Term - 3 */ + /* High Only - 1 (GPIO2 = 1 & GPIO3 = 0) */ + /* Disable - 0 (GPIO2 = 0 & GPIO3 = X) */ + + uint16_t isp_parameter; /* 18, 19 */ + + union + { + uint16_t w; + struct + { + uint8_t enable_fast_posting :1; + uint8_t report_lvd_bus_transition :1; + uint8_t unused_2 :1; + uint8_t unused_3 :1; + uint8_t unused_4 :1; + uint8_t unused_5 :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + uint8_t unused_8 :1; + uint8_t unused_9 :1; + uint8_t unused_10 :1; + uint8_t unused_11 :1; + uint8_t unused_12 :1; + uint8_t unused_13 :1; + uint8_t unused_14 :1; + uint8_t unused_15 :1; + }f; + }firmware_feature; /* 20, 21 */ + + uint16_t unused_22; /* 22, 23 */ + + struct + { + struct + { + uint8_t initiator_id :4; + uint8_t scsi_reset_disable :1; + uint8_t scsi_bus_size :1; + uint8_t scsi_bus_type :1; + uint8_t unused_7 :1; + }config_1; /* 24 */ + + uint8_t bus_reset_delay; /* 25 */ + uint8_t retry_count; /* 26 */ + uint8_t retry_delay; /* 27 */ + /* Adapter Capabilities bits */ + struct + { + uint8_t async_data_setup_time :4; + uint8_t req_ack_active_negation :1; + uint8_t data_line_active_negation :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + }config_2; /* 28 */ + + uint8_t unused_29; /* 29 */ + + uint16_t selection_timeout; /* 30, 31 */ + uint16_t max_queue_depth; /* 32, 33 */ + + uint16_t unused_34; /* 34, 35 */ + uint16_t unused_36; /* 36, 37 */ + uint16_t unused_38; /* 38, 39 */ + + struct + { + union + { + uint8_t c; + struct + { + uint8_t renegotiate_on_error :1; + uint8_t stop_queue_on_check :1; + uint8_t auto_request_sense :1; + uint8_t tag_queuing :1; + uint8_t sync_data_transfers :1; + uint8_t wide_data_transfers :1; + uint8_t parity_checking :1; + uint8_t disconnect_allowed :1; + }f; + }parameter; /* 40 */ + + uint8_t execution_throttle; /* 41 */ + uint8_t sync_period; /* 42 */ + + struct + { + uint8_t sync_offset :5; + uint8_t device_enable :1; + uint8_t unused_6 :1; + uint8_t unused_7 :1; + uint8_t ppr_options :4; + uint8_t ppr_bus_width :2; + uint8_t unused_8 :1; + uint8_t enable_ppr :1; + }flags; /* 43, 44 */ + + uint8_t unused_45; /* 45 */ + }target[MAX_TARGETS]; + }bus[MAX_BUSES]; + + uint16_t unused_248; /* 248, 249 */ + + uint16_t subsystem_id[2]; /* 250, 251, 252, 253 */ + + uint8_t System_Id_Pointer; /* 254 */ + + uint8_t chksum; /* 255 */ +}nvram160_t; + +/* + * ISP queue - command entry structure definition. + */ +#define MAX_CMDSZ 12 /* SCSI maximum CDB size. */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define COMMAND_TYPE 1 /* Command entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t lun; /* SCSI LUN */ + uint8_t target; /* SCSI ID */ + uint16_t cdb_len; /* SCSI command length. */ + uint16_t control_flags; /* Control flags. */ + uint16_t reserved; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ + uint32_t dseg_3_address; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ +}cmd_entry_t; + +/* + * ISP queue - continuation entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_TYPE 2 /* Continuation entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved; /* Reserved */ + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ + uint32_t dseg_3_address; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ + uint32_t dseg_4_address; /* Data segment 4 address. */ + uint32_t dseg_4_length; /* Data segment 4 length. */ + uint32_t dseg_5_address; /* Data segment 5 address. */ + uint32_t dseg_5_length; /* Data segment 5 length. */ + uint32_t dseg_6_address; /* Data segment 6 address. */ + uint32_t dseg_6_length; /* Data segment 6 length. */ +}cont_entry_t; + +/* + * ISP queue - status entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define STATUS_TYPE 3 /* Status entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + #define RF_CONT BIT_0 /* Continuation. */ + #define RF_FULL BIT_1 /* Full */ + #define RF_BAD_HEADER BIT_2 /* Bad header. */ + #define RF_BAD_PAYLOAD BIT_3 /* Bad payload. */ + uint32_t handle; /* System handle. */ + uint16_t scsi_status; /* SCSI status. */ + uint16_t comp_status; /* Completion status. */ + uint16_t state_flags; /* State flags. */ + #define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */ + #define SF_GOT_SENSE BIT_13 /* Got Sense */ + #define SF_GOT_STATUS BIT_12 /* Got Status */ + #define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */ + #define SF_SENT_CDB BIT_10 /* Send CDB */ + #define SF_GOT_TARGET BIT_9 /* */ + #define SF_GOT_BUS BIT_8 /* */ + uint16_t status_flags; /* Status flags. */ + uint16_t time; /* Time. */ + uint16_t req_sense_length; /* Request sense data length. */ + uint32_t residual_length; /* Residual transfer length. */ + uint16_t reserved[4]; + uint8_t req_sense_data[32]; /* Request sense data. */ +}sts_entry_t, response_t; + +/* + * ISP queue - marker entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define MARKER_TYPE 4 /* Marker entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved; + uint8_t lun; /* SCSI LUN */ + uint8_t target; /* SCSI ID */ + uint8_t modifier; /* Modifier (7-0). */ + #define MK_SYNC_ID_LUN 0 /* Synchronize ID/LUN */ + #define MK_SYNC_ID 1 /* Synchronize ID */ + #define MK_SYNC_ALL 2 /* Synchronize all ID/LUN */ + uint8_t reserved_1[53]; +}mrk_entry_t; + +/* + * ISP queue - extended command entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define EXTENDED_CMD_TYPE 5 /* Extended command entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t lun; /* SCSI LUN */ + uint8_t target; /* SCSI ID */ + uint16_t cdb_len; /* SCSI command length. */ + uint16_t control_flags; /* Control flags. */ + uint16_t reserved; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[88]; /* SCSI command words. */ +}ecmd_entry_t; + +/* + * ISP queue - 64-Bit addressing, command entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define COMMAND_A64_TYPE 9 /* Command A64 entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t handle; /* System handle. */ + uint8_t lun; /* SCSI LUN */ + uint8_t target; /* SCSI ID */ + uint16_t cdb_len; /* SCSI command length. */ + uint16_t control_flags; /* Control flags. */ + uint16_t reserved; + uint16_t timeout; /* Command timeout. */ + uint16_t dseg_count; /* Data segment count. */ + uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ + uint32_t reserved_1[2]; /* unused */ + uint32_t dseg_0_address[2]; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address[2]; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ +}cmd_a64_entry_t, request_t; + +/* + * ISP queue - 64-Bit addressing, continuation entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_A64_TYPE 0xA /* Continuation A64 entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t sys_define; /* System defined. */ + uint8_t entry_status; /* Entry Status. */ + uint32_t dseg_0_address[2]; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address[2]; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address[2]; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ + uint32_t dseg_3_address[2]; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ + uint32_t dseg_4_address[2]; /* Data segment 4 address. */ + uint32_t dseg_4_length; /* Data segment 4 length. */ +}cont_a64_entry_t; + +/* + * ISP queue - enable LUN entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define ENABLE_LUN_TYPE 0xB /* Enable LUN entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status not used. */ + uint32_t reserved_2; + uint16_t lun; /* Bit 15 is bus number. */ + uint16_t reserved_4; + uint32_t option_flags; + uint8_t status; + uint8_t reserved_5; + uint8_t command_count; /* Number of ATIOs allocated. */ + uint8_t immed_notify_count; /* Number of Immediate Notify */ + /* entries allocated. */ + uint8_t group_6_length; /* SCSI CDB length for group 6 */ + /* commands (2-26). */ + uint8_t group_7_length; /* SCSI CDB length for group 7 */ + /* commands (2-26). */ + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t reserved_6[20]; +}elun_entry_t; + +/* + * ISP queue - modify LUN entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define MODIFY_LUN_TYPE 0xC /* Modify LUN entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t reserved_3; + uint8_t operators; + uint8_t reserved_4; + uint32_t option_flags; + uint8_t status; + uint8_t reserved_5; + uint8_t command_count; /* Number of ATIOs allocated. */ + uint8_t immed_notify_count; /* Number of Immediate Notify */ + /* entries allocated. */ + uint16_t reserved_6; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t reserved_7[20]; +}modify_lun_entry_t; + +/* + * ISP queue - immediate notify entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define IMMED_NOTIFY_TYPE 0xD /* Immediate notify entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t reserved_4; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + /* entries allocated. */ + uint16_t seq_id; + uint8_t scsi_msg[8]; /* SCSI message not handled by ISP */ + uint16_t reserved_5[8]; + uint8_t sense_data[18]; +}notify_entry_t; + +/* + * ISP queue - notify acknowledge entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define NOTIFY_ACK_TYPE 0xE /* Notify acknowledge entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t event; + uint16_t seq_id; + uint16_t reserved_4[22]; +}nack_entry_t; + +/* + * ISP queue - Accept Target I/O (ATIO) entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define ACCEPT_TGT_IO_TYPE 6 /* Accept target I/O entry. */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; + uint8_t initiator_id; + uint8_t cdb_len; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint8_t cdb[26]; + uint8_t sense_data[18]; +}atio_entry_t; + +/* + * ISP queue - Continue Target I/O (CTIO) entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CONTINUE_TGT_IO_TYPE 7 /* CTIO entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint32_t transfer_length; + uint32_t residual; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ + uint32_t dseg_2_address; /* Data segment 2 address. */ + uint32_t dseg_2_length; /* Data segment 2 length. */ + uint32_t dseg_3_address; /* Data segment 3 address. */ + uint32_t dseg_3_length; /* Data segment 3 length. */ +}ctio_entry_t; + +/* + * ISP queue - CTIO returned entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_RET_TYPE 7 /* CTIO return entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint32_t transfer_length; + uint32_t residual; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint32_t dseg_0_address; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address; /* Data segment 1 address. */ + uint16_t dseg_1_length; /* Data segment 1 length. */ + uint8_t sense_data[18]; +}ctio_ret_entry_t; + +/* + * ISP queue - CTIO A64 entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_A64_TYPE 0xF /* CTIO A64 entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint32_t transfer_length; + uint32_t residual; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint32_t reserved_4[2]; + uint32_t dseg_0_address[2]; /* Data segment 0 address. */ + uint32_t dseg_0_length; /* Data segment 0 length. */ + uint32_t dseg_1_address[2]; /* Data segment 1 address. */ + uint32_t dseg_1_length; /* Data segment 1 length. */ +}ctio_a64_entry_t; + +/* + * ISP queue - CTIO returned entry structure definition. + */ +typedef struct +{ + uint8_t entry_type; /* Entry type. */ + #define CTIO_A64_RET_TYPE 0xF /* CTIO A64 returned entry */ + uint8_t entry_count; /* Entry count. */ + uint8_t reserved_1; + uint8_t entry_status; /* Entry Status. */ + uint32_t reserved_2; + uint8_t lun; /* SCSI LUN */ + uint8_t initiator_id; + uint8_t reserved_3; + uint8_t target_id; + uint32_t option_flags; + uint8_t status; + uint8_t scsi_status; + uint8_t tag_value; /* Received queue tag message value */ + uint8_t tag_type; /* Received queue tag message type */ + uint32_t transfer_length; + uint32_t residual; + uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + uint16_t dseg_count; /* Data segment count. */ + uint16_t reserved_4[7]; + uint8_t sense_data[18]; +}ctio_a64_ret_entry_t; + +/* + * ISP request and response queue entry sizes + */ +#define RESPONSE_ENTRY_SIZE (sizeof(response_t)) +#define REQUEST_ENTRY_SIZE (sizeof(request_t)) + +/* + * ISP status entry - completion status definitions. + */ +#define CS_COMPLETE 0x0 /* No errors */ +#define CS_INCOMPLETE 0x1 /* Incomplete transfer of cmd. */ +#define CS_DMA 0x2 /* A DMA direction error. */ +#define CS_TRANSPORT 0x3 /* Transport error. */ +#define CS_RESET 0x4 /* SCSI bus reset occurred */ +#define CS_ABORTED 0x5 /* System aborted command. */ +#define CS_TIMEOUT 0x6 /* Timeout error. */ +#define CS_DATA_OVERRUN 0x7 /* Data overrun. */ +#define CS_COMMAND_OVERRUN 0x8 /* Command Overrun. */ +#define CS_STATUS_OVERRUN 0x9 /* Status Overrun. */ +#define CS_BAD_MSG 0xA /* Bad msg after status phase. */ +#define CS_NO_MSG_OUT 0xB /* No msg out after selection. */ +#define CS_EXTENDED_ID 0xC /* Extended ID failed. */ +#define CS_IDE_MSG 0xD /* Target rejected IDE msg. */ +#define CS_ABORT_MSG 0xE /* Target rejected abort msg. */ +#define CS_REJECT_MSG 0xF /* Target rejected reject msg. */ +#define CS_NOP_MSG 0x10 /* Target rejected NOP msg. */ +#define CS_PARITY_MSG 0x11 /* Target rejected parity msg. */ +#define CS_DEV_RESET_MSG 0x12 /* Target rejected dev rst msg. */ +#define CS_ID_MSG 0x13 /* Target rejected ID msg. */ +#define CS_FREE 0x14 /* Unexpected bus free. */ +#define CS_DATA_UNDERRUN 0x15 /* Data Underrun. */ +#define CS_TRANACTION_1 0x18 /* Transaction error 1 */ +#define CS_TRANACTION_2 0x19 /* Transaction error 2 */ +#define CS_TRANACTION_3 0x1a /* Transaction error 3 */ +#define CS_INV_ENTRY_TYPE 0x1b /* Invalid entry type */ +#define CS_DEV_QUEUE_FULL 0x1c /* Device queue full */ +#define CS_PHASED_SKIPPED 0x1d /* SCSI phase skipped */ +#define CS_ARS_FAILED 0x1e /* ARS failed */ +#define CS_LVD_BUS_ERROR 0x21 /* LVD bus error */ +#define CS_BAD_PAYLOAD 0x80 /* Driver defined */ +#define CS_UNKNOWN 0x81 /* Driver defined */ +#define CS_RETRY 0x82 /* Driver defined */ + +/* + * ISP status entry - SCSI status byte bit definitions. + */ +#define SS_CHECK_CONDITION BIT_1 +#define SS_CONDITION_MET BIT_2 +#define SS_BUSY_CONDITION BIT_3 +#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3) + +/* + * ISP target entries - Option flags bit definitions. + */ +#define OF_ENABLE_TAG BIT_1 /* Tagged queue action enable */ +#define OF_DATA_IN BIT_6 /* Data in to initiator */ + /* (data from target to initiator) */ +#define OF_DATA_OUT BIT_7 /* Data out from initiator */ + /* (data from initiator to target) */ +#define OF_NO_DATA (BIT_7 | BIT_6) +#define OF_DISC_DISABLED BIT_15 /* Disconnects disabled */ +#define OF_DISABLE_SDP BIT_24 /* Disable sending save data ptr */ +#define OF_SEND_RDP BIT_26 /* Send restore data pointers msg */ +#define OF_FORCE_DISC BIT_30 /* Disconnects mandatory */ +#define OF_SSTS BIT_31 /* Send SCSI status */ + +#if QL1280_TARGET_MODE_SUPPORT +/* + * Target Read/Write buffer structure. + */ +#define TARGET_DATA_OFFSET 4 +#define TARGET_DATA_SIZE 0x2000 /* 8K */ +#define TARGET_INQ_OFFSET (TARGET_DATA_OFFSET + TARGET_DATA_SIZE) +#define TARGET_SENSE_SIZE 18 +#define TARGET_BUF_SIZE 36 + +typedef struct +{ + uint8_t hdr[4]; + uint8_t data[TARGET_DATA_SIZE]; + struct ident inq; +}tgt_t; +#endif + +/* + * BUS parameters/settings structure + */ +typedef struct +{ + uint8_t id; /* Host adapter SCSI id */ + uint8_t bus_reset_delay; /* SCSI bus reset delay. */ + uint8_t failed_reset_count; /* number of time reset failed */ + uint8_t unused; + uint16_t device_enables; /* Device enable bits. */ + uint16_t lun_disables; /* LUN disable bits. */ + uint16_t qtag_enables; /* Tag queue enables. */ + uint16_t hiwat; /* High water mark per device. */ + uint8_t reset_marker :1; + uint8_t disable_scsi_reset :1; + uint8_t scsi_bus_dead :1; /* SCSI Bus is Dead, when 5 back to back resets failed */ + +}bus_param_t; + +/* + * Linux Host Adapter structure + */ +typedef struct scsi_qla_host +{ + /* Linux adapter configuration data */ + struct Scsi_Host *host; /* pointer to host data */ + struct scsi_qla_host *next; + device_reg_t *iobase; /* Base Memory-mapped I/O address */ + uint8_t pci_bus; + uint8_t pci_device_fn; + uint8_t devnum; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,95) + struct pci_dev *pdev; +#endif + volatile unsigned char *mmpbase; /* memory mapped address */ + unsigned long host_no; + unsigned long instance; + uint8_t revision; + uint8_t ports; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) + spinlock_t spin_lock; +#endif + volatile unsigned char cpu_lock_count[NR_CPUS]; + unsigned long actthreads; + unsigned long qthreads; + unsigned long isr_count; /* Interrupt count */ + unsigned long spurious_int; + + uint32_t device_id; + + /* Outstandings ISP commands. */ + srb_t *outstanding_cmds[MAX_OUTSTANDING_COMMANDS]; + + /* BUS configuration data */ + bus_param_t bus_settings[MAX_BUSES]; + + /* Device LUN queues. */ + scsi_lu_t *dev[MAX_EQ]; /* Logical unit queues */ + +#ifdef UNUSED + /* Interrupt lock, and data */ + uint8_t intr_lock; /* Lock for interrupt locking */ +#endif + + /* bottom half run queue */ + struct tq_struct run_qla_bh; + + /* Received ISP mailbox data. */ + volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; + +#ifdef UNUSED + /* ISP ring lock, rings, and indexes */ + uint8_t ring_lock; /* ISP ring lock */ + struct timer_list dev_timer[MAX_TARGETS]; +#endif + + request_t req[REQUEST_ENTRY_CNT+1]; + response_t res[RESPONSE_ENTRY_CNT+1]; + unsigned long request_dma; /* Physical address. */ + request_t *request_ring; /* Base virtual address */ + request_t *request_ring_ptr; /* Current address. */ + uint16_t req_ring_index; /* Current index. */ + uint16_t req_q_cnt; /* Number of available entries. */ + + unsigned long response_dma; /* Physical address. */ + response_t *response_ring; /* Base virtual address */ + response_t *response_ring_ptr; /* Current address. */ + uint16_t rsp_ring_index; /* Current index. */ + +#if QL1280_TARGET_MODE_SUPPORT + /* Target buffer and sense data. */ + uint32_t tbuf_dma; /* Physical address. */ + tgt_t *tbuf; + uint32_t tsense_dma; /* Physical address. */ + uint8_t *tsense; +#endif + +#if WATCHDOGTIMER + /* Watchdog queue, lock and total timer */ + uint8_t watchdog_q_lock; /* Lock for watchdog queue */ + srb_t *wdg_q_first; /* First job on watchdog queue */ + srb_t *wdg_q_last; /* Last job on watchdog queue */ + uint32_t total_timeout; /* Total timeout (quantum count) */ + uint32_t watchdogactive; +#endif + + srb_t *done_q_first; /* First job on done queue */ + srb_t *done_q_last; /* Last job on done queue */ + + volatile struct + { + uint32_t watchdog_enabled :1; /* 0 */ + uint32_t mbox_int :1; /* 1 */ + uint32_t mbox_busy :1; /* 2 */ + uint32_t online :1; /* 3 */ + uint32_t reset_marker :1; /* 4 */ + uint32_t isp_abort_needed :1; /* 5 */ + uint32_t pci_64bit_slot :1; /* 6 */ + uint32_t disable_host_adapter :1; /* 7 */ + uint32_t reset_active :1; /* 8 */ + uint32_t abort_isp_active :1; /* 9 */ + uint32_t disable_risc_code_load :1; /* 10 */ + uint32_t enable_64bit_addressing :1; /* 11 */ +#define QLA1280_IN_ISR_BIT 12 + uint32_t in_isr :1; /* 12 */ + uint32_t in_abort :1; /* 13 */ + uint32_t in_reset :1; /* 14 */ + uint32_t dpc :1; /* 15 */ + uint32_t dpc_sched :1; /* 16 */ + uint32_t interrupts_on :1; /* 17 */ + }flags; + +}scsi_qla_host_t; + +/* + * Macros to help code, maintain, etc. + */ +#define SUBDEV(b, t, l) ( (b << (MAX_T_BITS + MAX_L_BITS)) | (t << MAX_L_BITS) | l) +#define LU_Q(ha, b, t, l) (ha->dev[SUBDEV(b, t, l)]) + +/* + * Locking Macro Definitions + * + * LOCK/UNLOCK definitions are lock/unlock primitives for multi-processor + * or spl/splx for uniprocessor. + */ +#define QLA1280_HIER HBA_HIER_BASE /* Locking hierarchy base for hba */ + +#define QLA1280_WATCHDOG_Q_LOCK(ha, p) +#define QLA1280_WATCHDOG_Q_UNLOCK(ha, p) + +#define QLA1280_SCSILU_LOCK(q) +#define QLA1280_SCSILU_UNLOCK(q) + +#define QLA1280_INTR_LOCK(ha) +#define QLA1280_INTR_UNLOCK(ha) + +#define QLA1280_RING_LOCK(ha) +#define QLA1280_RING_UNLOCK(ha) + +#if defined(__cplusplus) +} +#endif +/* + * Linux - SCSI Driver Interface Function Prototypes. + */ +int qla1280_proc_info ( char *, char **, off_t, int, int, int); +const char * qla1280_info(struct Scsi_Host *host); +int qla1280_detect(Scsi_Host_Template *); +int qla1280_release(struct Scsi_Host *); +const char * qla1280_info(struct Scsi_Host *); +int qla1280_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +int qla1280_abort(Scsi_Cmnd *); +int qla1280_reset(Scsi_Cmnd *, unsigned int); +int qla1280_biosparam(Disk *, kdev_t, int[]); +void qla1280_intr_handler(int, void *, struct pt_regs *); +void qla1280_setup(char *s, int *dummy); +#if defined(__386__) +# define QLA1280_BIOSPARAM qla1280_biosparam +#else +# define QLA1280_BIOSPARAM NULL +#endif + +/* + * Scsi_Host_template (see hosts.h) + * Device driver Interfaces to mid-level SCSI driver. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +/* This interface is now obsolete !!! */ +#define QLA1280_LINUX_TEMPLATE { \ + next: NULL, \ + usage_count: NULL, \ + proc_dir: NULL, \ + proc_info: NULL, \ + name: "Qlogic ISP 1280", \ + detect: qla1280_detect, \ + release: qla1280_release, \ + info: qla1280_info, \ + command: NULL, \ + queuecommand: qla1280_queuecommand, \ + abort: qla1280_abort, \ + reset: qla1280_reset, \ + slave_attach: NULL, \ + bios_param: QLA1280_BIOSPARAM, \ + can_queue: 255, /* MAX_OUTSTANDING_COMMANDS */ \ + this_id: -1, /* scsi id of host adapter */ \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 3, /* max commands per lun */ \ + present: 0, /* number of 1280s present */ \ + unchecked_isa_dma: 0, /* no memeory DMA restrictions */ \ + use_clustering: ENABLE_CLUSTERING \ +} +#else + +#define QLA1280_LINUX_TEMPLATE { \ + next: NULL, \ + module: NULL, \ + proc_dir: NULL, \ + proc_info: qla1280_proc_info, \ + name: "Qlogic ISP 1280\1080", \ + detect: qla1280_detect, \ + release: qla1280_release, \ + info: qla1280_info, \ + ioctl: NULL, \ + command: NULL, \ + queuecommand: qla1280_queuecommand, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: qla1280_abort, \ + reset: qla1280_reset, \ + slave_attach: NULL, \ + bios_param: QLA1280_BIOSPARAM, \ + can_queue: 255, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: SG_ALL, /* max scatter-gather cmds */\ + cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0, \ + emulated: 0 \ +} +#endif + + +#endif /* _IO_HBA_QLA1280_H */ diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.3.42/linux/drivers/scsi/qlogicisp.c Tue Jan 11 22:31:41 2000 +++ linux/drivers/scsi/qlogicisp.c Tue Feb 8 18:58:25 2000 @@ -508,6 +508,11 @@ */ #define RES_QUEUE_LEN ((QLOGICISP_REQ_QUEUE_LEN + 1) / 8 - 1) #define QUEUE_ENTRY_LEN 64 +#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) + +struct isp_queue_entry { + char __opaque[QUEUE_ENTRY_LEN]; +}; struct isp1020_hostdata { u_long memaddr; @@ -516,6 +521,9 @@ struct dev_param dev_param[MAX_TARGETS]; struct pci_dev *pci_dev; + struct isp_queue_entry *res_cpu; /* CPU-side address of response queue. */ + struct isp_queue_entry *req_cpu; /* CPU-size address of request queue. */ + /* result and request queues (shared with isp1020): */ u_int req_in_ptr; /* index of next request slot */ u_int res_out_ptr; /* index of next result slot */ @@ -523,8 +531,15 @@ /* this is here so the queues are nicely aligned */ long send_marker; /* do we need to send a marker? */ - char res[RES_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; - char req[QLOGICISP_REQ_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; + /* The cmd->handle has a fixed size, and is only 32-bits. We + * need to take care to handle 64-bit systems correctly thus what + * we actually place in cmd->handle is an index to the following + * table. Kudos to Matt Jacob for the technique. -DaveM + */ + Scsi_Cmnd *cmd_slots[QLOGICISP_REQ_QUEUE_LEN + 1]; + + dma_addr_t res_dma; /* PCI side view of response queue */ + dma_addr_t req_dma; /* PCI side view of request queue */ }; /* queue length's _must_ be power of two: */ @@ -616,10 +631,8 @@ hostdata->pci_dev = pdev; - if (isp1020_init(host)) { - scsi_unregister(host); - continue; - } + if (isp1020_init(host)) + goto fail_and_unregister; if (isp1020_reset_hardware(host) #if USE_NVRAM_DEFAULTS @@ -630,8 +643,7 @@ || isp1020_load_parameters(host)) { iounmap((void *)hostdata->memaddr); release_region(host->io_port, 0xff); - scsi_unregister(host); - continue; + goto fail_and_unregister; } host->this_id = hostdata->host_param.initiator_scsi_id; @@ -643,8 +655,7 @@ host->irq); iounmap((void *)hostdata->memaddr); release_region(host->io_port, 0xff); - scsi_unregister(host); - continue; + goto fail_and_unregister; } isp_outw(0x0, host, PCI_SEMAPHORE); @@ -652,6 +663,20 @@ isp1020_enable_irqs(host); hosts++; + continue; + + fail_and_unregister: + if (hostdata->res_cpu) + pci_free_consistent(hostdata->pci_dev, + QSIZE(RES_QUEUE_LEN), + hostdata->res_cpu, + hostdata->res_dma); + if (hostdata->req_cpu) + pci_free_consistent(hostdata->pci_dev, + QSIZE(QLOGICISP_REQ_QUEUE_LEN), + hostdata->req_cpu, + hostdata->req_dma); + scsi_unregister(host); } LEAVE("isp1020_detect"); @@ -709,7 +734,7 @@ */ int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *)) { - int i, sg_count, n, num_free; + int i, n, num_free; u_int in_ptr, out_ptr; struct dataseg * ds; struct scatterlist *sg; @@ -732,7 +757,7 @@ DEBUG(printk("qlogicisp : request queue depth %d\n", REQ_QUEUE_DEPTH(in_ptr, out_ptr))); - cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + cmd = (struct Command_Entry *) &hostdata->req_cpu[in_ptr]; in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; if (in_ptr == out_ptr) { printk("qlogicisp : request queue overflow\n"); @@ -760,7 +785,7 @@ printk("qlogicisp : request queue overflow\n"); return 1; } - cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + cmd = (struct Command_Entry *) &hostdata->req_cpu[in_ptr]; in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; } @@ -771,7 +796,6 @@ cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; - cmd->handle = cpu_to_le32((u_int) virt_to_bus(Cmnd)); cmd->target_lun = Cmnd->lun; cmd->target_id = Cmnd->target; cmd->cdb_length = cpu_to_le16(Cmnd->cmd_len); @@ -781,17 +805,22 @@ memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { - cmd->segment_cnt = cpu_to_le16(sg_count = Cmnd->use_sg); + int sg_count; + sg = (struct scatterlist *) Cmnd->request_buffer; ds = cmd->dataseg; + sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg); + + cmd->segment_cnt = cpu_to_le16(sg_count); + /* fill in first four sg entries: */ n = sg_count; if (n > 4) n = 4; for (i = 0; i < n; i++) { - ds[i].d_base = cpu_to_le32((u_int) virt_to_bus(sg->address)); - ds[i].d_count = cpu_to_le32(sg->length); + ds[i].d_base = cpu_to_le32(sg_dma_address(sg)); + ds[i].d_count = cpu_to_le32(sg_dma_len(sg)); ++sg; } sg_count -= 4; @@ -799,7 +828,7 @@ while (sg_count > 0) { ++cmd->hdr.entry_cnt; cont = (struct Continuation_Entry *) - &hostdata->req[in_ptr][0]; + &hostdata->req_cpu[in_ptr]; in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; if (in_ptr == out_ptr) { printk("isp1020: unexpected request queue " @@ -817,20 +846,29 @@ if (n > 7) n = 7; for (i = 0; i < n; ++i) { - ds[i].d_base = cpu_to_le32((u_int)virt_to_bus(sg->address)); - ds[i].d_count = cpu_to_le32(sg->length); + ds[i].d_base = cpu_to_le32(sg_dma_address(sg)); + ds[i].d_count = cpu_to_le32(sg_dma_len(sg)); ++sg; } sg_count -= n; } } else { + Cmnd->SCp.ptr = (char *)(unsigned long) + pci_map_single(hostdata->pci_dev, + Cmnd->request_buffer, + Cmnd->request_bufflen); + cmd->dataseg[0].d_base = - cpu_to_le32((u_int) virt_to_bus(Cmnd->request_buffer)); + cpu_to_le32((u32)(long)Cmnd->SCp.ptr); cmd->dataseg[0].d_count = - cpu_to_le32((u_int) Cmnd->request_bufflen); + cpu_to_le32((u32)Cmnd->request_bufflen); cmd->segment_cnt = cpu_to_le16(1); } + /* Committed, record Scsi_Cmd so we can find it later. */ + cmd->handle = in_ptr; + hostdata->cmd_slots[in_ptr] = Cmnd; + isp_outw(in_ptr, host, MBOX4); hostdata->req_in_ptr = in_ptr; @@ -905,10 +943,14 @@ QUEUE_DEPTH(in_ptr, out_ptr, RES_QUEUE_LEN))); while (out_ptr != in_ptr) { - sts = (struct Status_Entry *) &hostdata->res[out_ptr][0]; + u_int cmd_slot; + + sts = (struct Status_Entry *) &hostdata->res_cpu[out_ptr]; out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; - Cmnd = (Scsi_Cmnd *) bus_to_virt(le32_to_cpu(sts->handle)); + cmd_slot = sts->handle; + Cmnd = hostdata->cmd_slots[cmd_slot]; + hostdata->cmd_slots[cmd_slot] = NULL; TRACE("done", out_ptr, Cmnd); @@ -928,6 +970,15 @@ else Cmnd->result = DID_ERROR << 16; + if (Cmnd->use_sg) + pci_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, + Cmnd->use_sg); + else + pci_unmap_single(hostdata->pci_dev, + (u32)((long)Cmnd->SCp.ptr), + Cmnd->request_bufflen); + isp_outw(out_ptr, host, MBOX5); (*Cmnd->scsi_done)(Cmnd); } @@ -1031,19 +1082,25 @@ struct Scsi_Host *host; struct isp1020_hostdata *hostdata; int return_status = SCSI_ABORT_SUCCESS; - u_int cmdaddr = virt_to_bus(Cmnd); + u_int cmd_cookie; + int i; ENTER("isp1020_abort"); host = Cmnd->host; hostdata = (struct isp1020_hostdata *) host->hostdata; + for (i = 0; i < QLOGICISP_REQ_QUEUE_LEN + 1; i++) + if (hostdata->cmd_slots[i] == Cmnd) + break; + cmd_cookie = i; + isp1020_disable_irqs(host); param[0] = MBOX_ABORT; param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; - param[2] = cmdaddr >> 16; - param[3] = cmdaddr & 0xffff; + param[2] = cmd_cookie >> 16; + param[3] = cmd_cookie & 0xffff; isp1020_mbox_command(host, param); @@ -1313,6 +1370,26 @@ sh->max_id = MAX_TARGETS; sh->max_lun = MAX_LUNS; + hostdata->res_cpu = pci_alloc_consistent(hostdata->pci_dev, + QSIZE(RES_QUEUE_LEN), + &hostdata->res_dma); + if (hostdata->res_cpu == NULL) { + printk("qlogicisp : can't allocate response queue\n"); + return 1; + } + + hostdata->req_cpu = pci_alloc_consistent(hostdata->pci_dev, + QSIZE(QLOGICISP_REQ_QUEUE_LEN), + &hostdata->req_dma); + if (hostdata->req_cpu == NULL) { + pci_free_consistent(hostdata->pci_dev, + QSIZE(RES_QUEUE_LEN), + hostdata->res_cpu, + hostdata->res_dma); + printk("qlogicisp : can't allocate request queue\n"); + return 1; + } + LEAVE("isp1020_init"); return 0; @@ -1667,7 +1744,7 @@ } } - queue_addr = (u_int) virt_to_bus(&hostdata->res[0][0]); + queue_addr = hostdata->res_dma; param[0] = MBOX_INIT_RES_QUEUE; param[1] = RES_QUEUE_LEN + 1; @@ -1684,7 +1761,7 @@ return 1; } - queue_addr = (u_int) virt_to_bus(&hostdata->req[0][0]); + queue_addr = hostdata->req_dma; param[0] = MBOX_INIT_REQ_QUEUE; param[1] = QLOGICISP_REQ_QUEUE_LEN + 1; diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.3.42/linux/drivers/scsi/scsi.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/scsi.c Wed Feb 9 18:40:23 2000 @@ -147,7 +147,7 @@ /* - * Function: scsi_get_request_handler() + * Function: scsi_initialize_queue() * * Purpose: Selects queue handler function for a device. * @@ -165,20 +165,17 @@ * For this case, we have a special handler function, which * does some checks and ultimately calls scsi_request_fn. * - * As a future enhancement, it might be worthwhile to add support - * for stacked handlers - there might get to be too many permutations - * otherwise. Then again, we might just have one handler that does - * all of the special cases (a little bit slower), and those devices - * that don't need the special case code would directly call - * scsi_request_fn. - * - * As it stands, I can think of a number of special cases that - * we might need to handle. This would not only include the blocked - * case, but single_lun (for changers), and any special handling - * we might need for a spun-down disk to spin it back up again. + * The single_lun feature is a similar special case. + * + * We handle these things by stacking the handlers. The + * special case handlers simply check a few conditions, + * and return if they are not supposed to do anything. + * In the event that things are OK, then they call the next + * handler in the list - ultimately they call scsi_request_fn + * to do the dirty deed. */ -request_fn_proc * scsi_get_request_handler(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) { - return scsi_request_fn; +void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) { + blk_init_queue(&SDpnt->request_queue, scsi_request_fn); } #ifdef MODULE @@ -530,7 +527,7 @@ #endif struct Scsi_Host *host; int rtn = 0; - unsigned long flags; + unsigned long flags = 0; unsigned long timeout; ASSERT_LOCK(&io_request_lock, 0); @@ -1075,45 +1072,46 @@ int scsi_loadable_module_flag; /* Set after we scan builtin drivers */ -void *scsi_init_malloc(unsigned int size, int gfp_mask) -{ - void *retval; - - /* - * For buffers used by the DMA pool, we assume page aligned - * structures. - */ - if ((size % PAGE_SIZE) == 0) { - int order, a_size; - for (order = 0, a_size = PAGE_SIZE; - a_size < size; order++, a_size <<= 1); - retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order); - } else - retval = kmalloc(size, gfp_mask); - - if (retval) - memset(retval, 0, size); - return retval; -} - - -void scsi_init_free(char *ptr, unsigned int size) +/* + * Function: scsi_release_commandblocks() + * + * Purpose: Release command blocks associated with a device. + * + * Arguments: SDpnt - device + * + * Returns: Nothing + * + * Lock status: No locking assumed or required. + * + * Notes: + */ +void scsi_release_commandblocks(Scsi_Device * SDpnt) { - /* - * We need this special code here because the DMA pool assumes - * page aligned data. Besides, it is wasteful to allocate - * page sized chunks with kmalloc. - */ - if ((size % PAGE_SIZE) == 0) { - int order, a_size; + Scsi_Cmnd *SCpnt; + unsigned long flags; - for (order = 0, a_size = PAGE_SIZE; - a_size < size; order++, a_size <<= 1); - free_pages((unsigned long) ptr, order); - } else - kfree(ptr); + spin_lock_irqsave(&device_request_lock, flags); + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { + SDpnt->device_queue = SCpnt->next; + kfree((char *) SCpnt); + } + SDpnt->has_cmdblocks = 0; + spin_unlock_irqrestore(&device_request_lock, flags); } +/* + * Function: scsi_build_commandblocks() + * + * Purpose: Allocate command blocks associated with a device. + * + * Arguments: SDpnt - device + * + * Returns: Nothing + * + * Lock status: No locking assumed or required. + * + * Notes: + */ void scsi_build_commandblocks(Scsi_Device * SDpnt) { unsigned long flags; @@ -1129,9 +1127,10 @@ for (j = 0; j < SDpnt->queue_depth; j++) { SCpnt = (Scsi_Cmnd *) - scsi_init_malloc(sizeof(Scsi_Cmnd), + kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC | (host->unchecked_isa_dma ? GFP_DMA : 0)); + memset(SCpnt, 0, sizeof(Scsi_Cmnd)); if (NULL == SCpnt) break; /* If not, the next line will oops ... */ memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout)); @@ -1323,7 +1322,6 @@ static int proc_scsi_gen_write(struct file * file, const char * buf, unsigned long length, void *data) { - Scsi_Cmnd *SCpnt; struct Scsi_Device_Template *SDTpnt; Scsi_Device *scd; struct Scsi_Host *HBA_ptr; @@ -1537,10 +1535,8 @@ * Nobody is using this device any more. * Free all of the command structures. */ - for (SCpnt = scd->device_queue; SCpnt; SCpnt = SCpnt->next) { - scd->device_queue = SCpnt->next; - scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); - } + scsi_release_commandblocks(scd); + /* Now we can remove the device structure */ if (scd->next != NULL) scd->next->prev = scd->prev; @@ -1552,7 +1548,7 @@ HBA_ptr->host_queue = scd->next; } blk_cleanup_queue(&scd->request_queue); - scsi_init_free((char *) scd, sizeof(Scsi_Device)); + kfree((char *) scd); } else { goto out; } @@ -1865,17 +1861,12 @@ } for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = shpnt->host_queue) { - while (SDpnt->device_queue) { - SCpnt = SDpnt->device_queue->next; - scsi_init_free((char *) SDpnt->device_queue, sizeof(Scsi_Cmnd)); - SDpnt->device_queue = SCpnt; - } - SDpnt->has_cmdblocks = 0; + scsi_release_commandblocks(SDpnt); blk_cleanup_queue(&SDpnt->request_queue); /* Next free up the Scsi_Device structures for this host */ shpnt->host_queue = SDpnt->next; - scsi_init_free((char *) SDpnt, sizeof(Scsi_Device)); + kfree((char *) SDpnt); } } @@ -2023,7 +2014,6 @@ static int scsi_unregister_device(struct Scsi_Device_Template *tpnt) { Scsi_Device *SDpnt; - Scsi_Cmnd *SCpnt; struct Scsi_Host *shpnt; struct Scsi_Device_Template *spnt; struct Scsi_Device_Template *prev_spnt; @@ -2050,13 +2040,7 @@ * Nobody is using this device any more. Free all of the * command structures. */ - for (SCpnt = SDpnt->device_queue; SCpnt; - SCpnt = SCpnt->next) { - if (SCpnt == SDpnt->device_queue) - SDpnt->device_queue = SCpnt->next; - scsi_init_free((char *) SCpnt, sizeof(*SCpnt)); - } - SDpnt->has_cmdblocks = 0; + scsi_release_commandblocks(SDpnt); } } } @@ -2309,7 +2293,7 @@ Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt) { Scsi_Device * SDpnt; - Scsi_Cmnd * SCpnt; + /* * Attach a single Scsi_Device to the Scsi_Host - this should * be made to look like a "pseudo-device" that points to the @@ -2330,18 +2314,9 @@ SDpnt->type = -1; SDpnt->queue_depth = 1; - SCpnt = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); - memset(SCpnt, 0, sizeof(Scsi_Cmnd)); - SCpnt->host = SHpnt; - SCpnt->device = SDpnt; - SCpnt->target = SDpnt->id; - SCpnt->state = SCSI_STATE_UNUSED; - SCpnt->owner = SCSI_OWNER_NOBODY; - SCpnt->request.rq_status = RQ_INACTIVE; - - SDpnt->device_queue = SCpnt; + scsi_build_commandblocks(SDpnt); - blk_init_queue(&SDpnt->request_queue, scsi_get_request_handler(SDpnt, SDpnt->host)); + scsi_initialize_queue(SDpnt, SHpnt); blk_queue_headactive(&SDpnt->request_queue, 0); SDpnt->request_queue.queuedata = (void *) SDpnt; @@ -2380,7 +2355,7 @@ * We only have a single SCpnt attached to this device. Free * it now. */ - kfree(SDpnt->device_queue); + scsi_release_commandblocks(SDpnt); kfree(SDpnt); } diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.3.42/linux/drivers/scsi/scsi.h Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/scsi.h Wed Feb 9 21:34:43 2000 @@ -415,8 +415,7 @@ /* * Prototypes for functions in scsi_lib.c */ -extern void scsi_maybe_unblock_host(Scsi_Device * SDpnt); -extern void scsi_blocked_request_fn(request_queue_t * q); +extern int scsi_maybe_unblock_host(Scsi_Device * SDpnt); extern Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors); extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *); @@ -426,13 +425,14 @@ int block_sectors); extern void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt); extern void scsi_request_fn(request_queue_t * q); - +extern int scsi_starvation_completion(Scsi_Device * SDpnt); /* * Prototypes for functions in scsi.c */ extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt); extern void scsi_bottom_half_handler(void); +extern void scsi_release_commandblocks(Scsi_Device * SDpnt); extern void scsi_build_commandblocks(Scsi_Device * SDpnt); extern void scsi_done(Scsi_Cmnd * SCpnt); extern void scsi_finish_command(Scsi_Cmnd *); @@ -447,6 +447,7 @@ void *buffer, unsigned bufflen, int timeout, int retries); extern int scsi_dev_init(void); + /* diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.3.42/linux/drivers/scsi/scsi_error.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/scsi/scsi_error.c Wed Feb 9 18:40:23 2000 @@ -972,9 +972,13 @@ * When the low level driver returns DID_SOFT_ERROR, * it is responsible for keeping an internal retry counter * in order to avoid endless loops (DB) + * + * Actually this is a bug in this function here. We should + * be mindful of the maximum number of retries specified + * and not get stuck in a loop. */ case DID_SOFT_ERROR: - return NEEDS_RETRY; + goto maybe_retry; case DID_BUS_BUSY: case DID_PARITY: @@ -1830,6 +1834,8 @@ */ if( host->loaded_as_module ) { siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); + } else { + siginitsetinv(¤t->blocked, 0); } lock_kernel(); @@ -1865,13 +1871,20 @@ * trying to unload a module. */ SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler sleeping\n")); - if( host->loaded_as_module ) { - down_interruptible(&sem); - if (signal_pending(current)) - break; - } else { - down(&sem); + /* + * Note - we always use down_interruptible with the semaphore + * even if the module was loaded as part of the kernel. The + * reason is that down() will cause this thread to be counted + * in the load average as a running process, and down + * interruptible doesn't. Given that we need to allow this + * thread to die if the driver was loaded as a module, using + * semaphores isn't unreasonable. + */ + down_interruptible(&sem); + if( host->loaded_as_module ) { + if (signal_pending(current)) + break; } SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n")); diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v2.3.42/linux/drivers/scsi/scsi_ioctl.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/scsi_ioctl.c Wed Feb 9 18:40:23 2000 @@ -323,7 +323,7 @@ { int i; printk("scsi_ioctl : device %d. command = ", dev->id); - for (i = 0; i < 12; ++i) + for (i = 0; i < cmdlen; ++i) printk("%02x ", cmd[i]); printk("\nbuffer ="); for (i = 0; i < 20; ++i) diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.3.42/linux/drivers/scsi/scsi_lib.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/scsi_lib.c Wed Feb 9 18:40:23 2000 @@ -50,12 +50,6 @@ * This entire source file deals with the new queueing code. */ -/* - * For hosts that request single-file access to the ISA bus, this is a pointer to - * the currently active host. - */ -volatile struct Scsi_Host *host_active = NULL; - /* * Function: scsi_insert_special_cmd() @@ -191,7 +185,6 @@ return 1; } - /* * Function: scsi_queue_next_request() * @@ -1009,4 +1002,21 @@ */ spin_lock_irq(&io_request_lock); } +} + +/* + * FIXME(eric) - these are empty stubs for the moment. I need to re-implement + * host blocking from scratch. The theory is that hosts that wish to block + * will register/deregister using these functions instead of the old way + * of setting the wish_block flag. + * + * The details of the implementation remain to be settled, however the + * stubs are here now so that the actual drivers will properly compile. + */ +void scsi_register_blocked_host(struct Scsi_Host * SHpnt) +{ +} + +void scsi_deregister_blocked_host(struct Scsi_Host * SHpnt) +{ } diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c --- v2.3.42/linux/drivers/scsi/scsi_merge.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/scsi/scsi_merge.c Mon Feb 7 19:45:28 2000 @@ -109,9 +109,7 @@ #define SANITY_CHECK(req, _CLUSTER, _DMA) \ if( req->nr_segments != __count_segments(req, _CLUSTER, _DMA, NULL) ) \ { \ - __label__ here; \ -here: \ - printk("Incorrect segment count at 0x%p", &&here); \ + printk("Incorrect segment count at 0x%p", current_text_addr()); \ dump_stats(req, _CLUSTER, _DMA, __count_segments(req, _CLUSTER, _DMA, NULL)); \ } #else diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c --- v2.3.42/linux/drivers/scsi/scsi_scan.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/scsi_scan.c Wed Feb 9 18:40:23 2000 @@ -42,7 +42,7 @@ 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, Scsi_Cmnd * SCpnt, + int *sparse_lun, Scsi_Device ** SDpnt, struct Scsi_Host *shpnt, char *scsi_result); struct dev_info { @@ -119,6 +119,7 @@ {"IOMEGA", "Io20S *F", "*", BLIST_KEY}, {"INSITE", "Floptical F*8I", "*", BLIST_KEY}, {"INSITE", "I325VM", "*", BLIST_KEY}, + {"LASOUND","CDX7405","3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, {"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN}, @@ -259,7 +260,6 @@ int dev; int lun; int max_dev_lun; - Scsi_Cmnd *SCpnt; unsigned char *scsi_result; unsigned char scsi_result0[256]; Scsi_Device *SDpnt; @@ -267,29 +267,26 @@ int sparse_lun; scsi_result = NULL; - SCpnt = (Scsi_Cmnd *) kmalloc(sizeof(Scsi_Cmnd), - GFP_ATOMIC | GFP_DMA); - if (SCpnt) { - memset(SCpnt, 0, sizeof(Scsi_Cmnd)); - SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), - GFP_ATOMIC); - if (SDpnt) { - memset(SDpnt, 0, sizeof(Scsi_Device)); - /* - * Register the queue for the device. All I/O requests will come - * in through here. We also need to register a pointer to - * ourselves, since the queue handler won't know what device - * the queue actually represents. We could look it up, but it - * is pointless work. - */ - blk_init_queue(&SDpnt->request_queue, scsi_get_request_handler(SDpnt, shpnt)); - blk_queue_headactive(&SDpnt->request_queue, 0); - SDpnt->request_queue.queuedata = (void *) SDpnt; - /* Make sure we have something that is valid for DMA purposes */ - scsi_result = ((!shpnt->unchecked_isa_dma) - ? &scsi_result0[0] : kmalloc(512, GFP_DMA)); - } + + SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), + GFP_ATOMIC); + if (SDpnt) { + memset(SDpnt, 0, sizeof(Scsi_Device)); + /* + * Register the queue for the device. All I/O requests will come + * in through here. We also need to register a pointer to + * ourselves, since the queue handler won't know what device + * the queue actually represents. We could look it up, but it + * is pointless work. + */ + scsi_initialize_queue(SDpnt, shpnt); + blk_queue_headactive(&SDpnt->request_queue, 0); + SDpnt->request_queue.queuedata = (void *) SDpnt; + /* Make sure we have something that is valid for DMA purposes */ + scsi_result = ((!shpnt->unchecked_isa_dma) + ? &scsi_result0[0] : kmalloc(512, GFP_DMA)); } + if (scsi_result == NULL) { printk("Unable to obtain scsi_result buffer\n"); goto leave; @@ -297,11 +294,12 @@ /* * We must chain ourself in the host_queue, so commands can time out */ - SCpnt->next = NULL; - SDpnt->device_queue = SCpnt; + SDpnt->queue_depth = 1; SDpnt->host = shpnt; SDpnt->online = TRUE; + scsi_build_commandblocks(SDpnt); + initialize_merge_fn(SDpnt); /* @@ -329,9 +327,6 @@ * We need to increment the counter for this one device so we can track when * things are quiet. */ - atomic_inc(&shpnt->host_active); - atomic_inc(&SDpnt->device_active); - if (hardcoded == 1) { Scsi_Device *oldSDpnt = SDpnt; struct Scsi_Device_Template *sdtpnt; @@ -345,7 +340,7 @@ if (lun >= shpnt->max_lun) goto leave; scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun, - &SDpnt, SCpnt, shpnt, scsi_result); + &SDpnt, shpnt, scsi_result); if (SDpnt != oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ @@ -397,7 +392,7 @@ 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, SCpnt, shpnt, + &sparse_lun, &SDpnt, shpnt, scsi_result) && !sparse_lun) break; /* break means don't probe further for luns!=0 */ @@ -407,13 +402,6 @@ } /* for channel ends */ } /* if/else hardcoded */ - /* - * We need to decrement the counter for this one device - * so we know when everything is quiet. - */ - atomic_dec(&shpnt->host_active); - atomic_dec(&SDpnt->device_active); - leave: { /* Unchain SCpnt from host_queue */ @@ -434,13 +422,12 @@ } } + scsi_release_commandblocks(SDpnt); + /* Last device block does not exist. Free memory. */ if (SDpnt != NULL) kfree((char *) SDpnt); - if (SCpnt != NULL) - kfree((char *) SCpnt); - /* If we allocated a buffer so we could do DMA, free it now */ if (scsi_result != &scsi_result0[0] && scsi_result != NULL) { kfree(scsi_result); @@ -464,13 +451,14 @@ * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. * Global variables used : scsi_devices(linked list) */ -int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun, - int *sparse_lun, Scsi_Device ** SDpnt2, Scsi_Cmnd * SCpnt, +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) { unsigned char scsi_cmd[MAX_COMMAND_SIZE]; struct Scsi_Device_Template *sdtpnt; Scsi_Device *SDtail, *SDpnt = *SDpnt2; + Scsi_Cmnd * SCpnt; int bflags, type = -1; static int ghost_channel=-1, ghost_dev=-1; int org_lun = lun; @@ -505,6 +493,8 @@ scsi_cmd[1] = lun << 5; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0; + SCpnt = scsi_allocate_device(SDpnt, 0, 0); + SCpnt->host = SDpnt->host; SCpnt->device = SDpnt; SCpnt->target = SDpnt->id; @@ -527,10 +517,14 @@ ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) && ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) && - ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0)) + ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0)) { + scsi_release_command(SCpnt); return 1; - } else + } + } else { + scsi_release_command(SCpnt); return 0; + } } SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n")); /* @@ -551,14 +545,17 @@ SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n", SCpnt->result ? "failed" : "successful", SCpnt->result)); - if (SCpnt->result) + if (SCpnt->result) { + scsi_release_command(SCpnt); return 0; /* assume no peripheral if any sort of error */ + } /* * Check the peripheral qualifier field - this tells us whether LUNS * are supported here or not. */ if ((scsi_result[0] >> 5) == 3) { + scsi_release_command(SCpnt); return 0; /* assume no peripheral if any sort of error */ } @@ -703,11 +700,11 @@ (void *) scsi_result, 0x2a, SCSI_TIMEOUT, 3); } - /* - * Detach the command from the device. It was just a temporary to be used while - * scanning the bus - the real ones will be allocated later. - */ - SDpnt->device_queue = NULL; + + scsi_release_command(SCpnt); + SCpnt = NULL; + + scsi_release_commandblocks(SDpnt); /* * This device was already hooked up to the host in question, @@ -715,13 +712,19 @@ * allocate a new one and attach it to the host so that we can further scan the bus. */ SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), GFP_ATOMIC); - *SDpnt2 = SDpnt; if (!SDpnt) { printk("scsi: scan_scsis_single: Cannot malloc\n"); return 0; } memset(SDpnt, 0, sizeof(Scsi_Device)); + *SDpnt2 = SDpnt; + SDpnt->queue_depth = 1; + SDpnt->host = shpnt; + SDpnt->online = TRUE; + + scsi_build_commandblocks(SDpnt); + /* * Register the queue for the device. All I/O requests will come * in through here. We also need to register a pointer to @@ -729,17 +732,15 @@ * the queue actually represents. We could look it up, but it * is pointless work. */ - blk_init_queue(&SDpnt->request_queue, scsi_get_request_handler(SDpnt, shpnt)); + scsi_initialize_queue(SDpnt, shpnt); blk_queue_headactive(&SDpnt->request_queue, 0); SDpnt->request_queue.queuedata = (void *) SDpnt; SDpnt->host = shpnt; initialize_merge_fn(SDpnt); /* - * And hook up our command block to the new device we will be testing - * for. + * Mark this device as online, or otherwise we won't be able to do much with it. */ - SDpnt->device_queue = SCpnt; SDpnt->online = TRUE; /* diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c --- v2.3.42/linux/drivers/scsi/scsi_syms.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/scsi/scsi_syms.c Wed Feb 9 18:40:23 2000 @@ -50,8 +50,6 @@ EXPORT_SYMBOL(scsi_do_cmd); EXPORT_SYMBOL(scsi_wait_cmd); EXPORT_SYMBOL(scsi_command_size); -EXPORT_SYMBOL(scsi_init_malloc); -EXPORT_SYMBOL(scsi_init_free); EXPORT_SYMBOL(scsi_ioctl); EXPORT_SYMBOL(print_command); EXPORT_SYMBOL(print_sense); @@ -79,6 +77,9 @@ EXPORT_SYMBOL(scsi_io_completion); EXPORT_SYMBOL(scsi_end_request); + +EXPORT_SYMBOL(scsi_register_blocked_host); +EXPORT_SYMBOL(scsi_deregister_blocked_host); /* * These are here only while I debug the rest of the scsi stuff. diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.3.42/linux/drivers/scsi/sd.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/scsi/sd.c Wed Feb 9 18:40:23 2000 @@ -960,15 +960,15 @@ return 0; rscsi_disks = (Scsi_Disk *) - scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); + kmalloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk)); /* for every (necessary) major: */ - sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + sd_sizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int)); - sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + sd_blocksizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + sd_hardsizes = (int *) kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); for (i = 0; i < sd_template.dev_max << 4; i++) { sd_blocksizes[i] = 1024; @@ -979,9 +979,10 @@ blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4); hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4); } - sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) * - sizeof(struct hd_struct), - GFP_ATOMIC); + sd = (struct hd_struct *) kmalloc((sd_template.dev_max << 4) * + sizeof(struct hd_struct), + GFP_ATOMIC); + memset(sd, 0, (sd_template.dev_max << 4) * sizeof(struct hd_struct)); if (N_USED_SD_MAJORS > 1) sd_gendisks = (struct gendisk *) @@ -1215,13 +1216,11 @@ sd_registered--; if (rscsi_disks != NULL) { - scsi_init_free((char *) rscsi_disks, - sd_template.dev_max * sizeof(Scsi_Disk)); - scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int)); - scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int)); - scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int)); - scsi_init_free((char *) sd, - (sd_template.dev_max << 4) * sizeof(struct hd_struct)); + kfree((char *) rscsi_disks); + kfree((char *) sd_sizes); + kfree((char *) sd_blocksizes); + kfree((char *) sd_hardsizes); + kfree((char *) sd); /* * Now remove sd_gendisks from the linked list diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.3.42/linux/drivers/scsi/sg.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/scsi/sg.c Thu Feb 10 12:37:22 2000 @@ -6,7 +6,7 @@ * * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard - * 2.x extensions to driver: + * Version 2 and 3 extensions to driver: * Copyright (C) 1998, 1999 Douglas Gilbert * * This program is free software; you can redistribute it and/or modify @@ -14,35 +14,29 @@ * the Free Software Foundation; either version 2, or (at your option) * any later version. * - * Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book. */ - static char * sg_version_str = "Version: 2.3.35 (990708)"; - static int sg_version_num = 20335; /* 2 digits for each component */ + static char * sg_version_str = "Version: 3.1.10 (20000123)"; + static int sg_version_num = 30110; /* 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 * the kernel/module needs to be built with CONFIG_SCSI_LOGGING - * (otherwise the macros compile to empty statements). - * Then before running the program to be debugged enter: - * # echo "scsi log timeout 7" > /proc/scsi/scsi + * (otherwise the macros compile to empty statements). + * Then before running the program to be debugged enter: + * # echo "scsi log timeout 7" > /proc/scsi/scsi * This will send copious output to the console and the log which * is usually /var/log/messages. To turn off debugging enter: - * # echo "scsi log timeout 0" > /proc/scsi/scsi + * # echo "scsi log timeout 0" > /proc/scsi/scsi * The 'timeout' token was chosen because it is relatively unused. * The token 'hlcomplete' should be used but that triggers too * much output from the sd device driver. To dump the current * state of the SCSI mid level data structures enter: - * # echo "scsi dump 1" > /proc/scsi/scsi - * To dump the state of sg's data structures get the 'sg_debug' - * program from the utilities and enter: - * # sg_debug /dev/sga - * or any valid sg device name. The state of _all_ sg devices - * will be sent to the console and the log. - * - * - The 'alt_address' field in the scatter_list structure and the - * related 'mem_src' indicate the source of the heap allocation. + * # echo "scsi dump 1" > /proc/scsi/scsi + * To dump the state of sg's data structures use: + * # cat /proc/scsi/sg/debug * */ +#include #include #include @@ -54,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -65,13 +60,29 @@ #include #include -static spinlock_t sg_request_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_PROC_FS +#include +static int sg_proc_init(void); +static void sg_proc_cleanup(void); +#endif + +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE */ + +/* #define SG_ALLOW_DIO */ +#ifdef SG_ALLOW_DIO +#include +#endif -int sg_big_buff = SG_DEF_RESERVED_SIZE; /* sg_big_buff is ro through sysctl */ -/* N.B. This global is here to keep existing software happy. It now holds - the size of the reserve buffer of the most recent sucessful sg_open(). - Only available when 'sg' compiled into kernel (rather than a module). - This is deprecated (use SG_GET_RESERVED_SIZE ioctl() instead). */ +int sg_big_buff = SG_DEF_RESERVED_SIZE; +/* N.B. This variable is readable and writeable via + /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer + of this size (or less if there is not enough memory) will be reserved + for use by this file descriptor. [Deprecated usage: this variable is also + 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 */ #define SG_SECTOR_SZ 512 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) @@ -81,17 +92,10 @@ static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS; -/* #define SG_DEBUG */ /* for counting varieties of allocations */ - -#ifdef SG_DEBUG -static int sg_num_kmal = 0; -static int sg_num_pool = 0; -static int sg_num_page = 0; -#endif - #define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */ #define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */ #define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */ +#define SG_USER_MEM 4 /* memory belongs to user space */ static int sg_init(void); @@ -100,28 +104,36 @@ static int sg_detect(Scsi_Device *); static void sg_detach(Scsi_Device *); +static Scsi_Cmnd * dummy_cmdp = 0; /* only used for sizeof */ + -struct Scsi_Device_Template sg_template = +static spinlock_t sg_request_lock = SPIN_LOCK_UNLOCKED; + +struct Scsi_Device_Template sg_template = { - tag:"sg", - scsi_type:0xff, - major:SCSI_GENERIC_MAJOR, - detect:sg_detect, - init:sg_init, - finish:sg_finish, - attach:sg_attach, - detach:sg_detach + tag:"sg", + scsi_type:0xff, + major:SCSI_GENERIC_MAJOR, + detect:sg_detect, + init:sg_init, + finish:sg_finish, + attach:sg_attach, + detach:sg_detach }; +/* Need to add 'rwlock_t sg_rw_lock = RW_LOCK_UNLOCKED;' for list protection */ typedef struct sg_scatter_hold /* holding area for scsi scatter gather info */ { - unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */ unsigned short sglist_len; /* size of malloc'd scatter-gather list */ unsigned bufflen; /* Size of (aggregate) data buffer */ unsigned b_malloc_len; /* actual len malloc'ed in buffer */ void * buffer; /* Data buffer or scatter list,12 bytes each*/ - char mem_src; /* heap whereabouts of 'buffer' */ + struct kiobuf * kiobp; /* for direct IO information */ + char mapped; /* indicates kiobp has locked pages */ + char buffer_mem_src; /* heap whereabouts of 'buffer' */ + unsigned char cmd_opcode; /* first byte of command */ } Sg_scatter_hold; /* 20 bytes long on i386 */ struct sg_device; /* forward declarations */ @@ -129,20 +141,23 @@ typedef struct sg_request /* SG_MAX_QUEUE requests outstanding per file */ { - Scsi_Cmnd * my_cmdp; /* NULL -> ready to read, else id */ + Scsi_Cmnd * my_cmdp; /* != 0 when request with lower levels */ struct sg_request * nextrp; /* NULL -> tail request (slist) */ struct sg_fd * parentfp; /* NULL -> not in use */ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ - struct sg_header header; /* scsi command+info, see */ + sg_io_hdr_t header; /* scsi command+info, see */ + unsigned char sense_b[sizeof(dummy_cmdp->sense_buffer)]; char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ -} Sg_request; /* 72 bytes long on i386 */ + char orphan; /* 1 -> drop on sight, 0 -> normal */ + char sg_io_owned; /* 1 -> packet belongs to SG_IO */ + char done; /* 1 -> bh handler done, 0 -> prior to bh */ +} Sg_request; /* 168 bytes long on i386 */ typedef struct sg_fd /* holds the state of a file descriptor */ { struct sg_fd * nextfp; /* NULL when last opened fd on this device */ struct sg_device * parentdp; /* owning device */ wait_queue_head_t read_wait; /* queue read until command done */ - wait_queue_head_t write_wait; /* write waits on pending read */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ Sg_scatter_hold reserve; /* buffer held for this file descriptor */ unsigned save_scat_len; /* original length of trunc. scat. element */ @@ -152,60 +167,73 @@ 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 */ - char my_mem_src; /* heap whereabouts of this Sg_fd object */ + char fd_mem_src; /* heap whereabouts of this Sg_fd object */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ - char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */ 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; /* 1212 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ { Scsi_Device * device; - wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ + wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ int sg_tablesize; /* adapter's max scatter-gather table size */ Sg_fd * headfp; /* first open fd belonging to this device */ kdev_t i_rdev; /* holds device major+minor number */ char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ - unsigned char merge_fd; /* 0->sequencing per fd, else fd count */ } Sg_device; /* 24 bytes long on i386 */ static int sg_fasync(int fd, struct file * filp, int mode); -static void sg_command_done(Scsi_Cmnd * SCpnt); -static int sg_start_req(Sg_request * srp, int max_buff_size, - const char * inp, int num_write_xfer); -static void sg_finish_rem_req(Sg_request * srp, char * outp, - int num_read_xfer); -static int sg_build_scat(Sg_scatter_hold * schp, int buff_size, - const Sg_fd * sfp); -static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp, - int num_write_xfer); +static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt); +static int sg_start_req(Sg_request * srp); +static void sg_finish_rem_req(Sg_request * srp); +static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); +static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp); +static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count, + Sg_request * srp); +static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count, + int blocking, int read_only, Sg_request ** o_srp); +static int sg_common_write(Sg_fd * sfp, Sg_request * srp, + unsigned char * cmnd, int timeout, int blocking); +static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind, + int wr_xf, int * countp, unsigned char ** up); +static int sg_write_xfer(Sg_request * srp); +static int sg_read_xfer(Sg_request * srp); +static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer); static void sg_remove_scat(Sg_scatter_hold * schp); -static void sg_read_xfer(Sg_scatter_hold * schp, char * outp, - int num_read_xfer); +static char * sg_get_sgat_msa(Sg_scatter_hold * schp); static void sg_build_reserve(Sg_fd * sfp, int req_size); static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size); static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp); -static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, +static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, int * mem_srcp); static void sg_free(char * buff, int size, int mem_src); -static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, +static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp); static void sg_low_free(char * buff, int size, int mem_src); -static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved); +static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev); static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id); static Sg_request * sg_add_request(Sg_fd * sfp); -static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp); +static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(const Sg_fd * sfp); +static int sg_dio_in_use(const Sg_fd * sfp); static void sg_clr_scpnt(Scsi_Cmnd * SCpnt); static void sg_shorten_timeout(Scsi_Cmnd * scpnt); -static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of); -static void sg_debug_all(const Sg_fd * sfp); +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); +static int sg_last_dev(void); +static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len); +static void sg_unmap_and(Sg_scatter_hold * schp, int free_also); 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); static int sg_open(struct inode * inode, struct file * filp) @@ -240,8 +268,8 @@ if (sdp->headfp && (filp->f_flags & O_NONBLOCK)) return -EBUSY; res = 0; /* following is a macro that beats race condition */ - __wait_event_interruptible(sdp->o_excl_wait, - ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), + __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 */ @@ -257,15 +285,9 @@ if (! sdp->headfp) { /* no existing opens on this device */ sdp->sgdebug = 0; sdp->sg_tablesize = sdp->device->host->sg_tablesize; - sdp->merge_fd = 0; /* A little tricky if SG_DEF_MERGE_FD set */ } - if ((sfp = sg_add_sfp(sdp, dev, O_RDWR == (flags & O_ACCMODE)))) { + if ((sfp = sg_add_sfp(sdp, dev))) filp->private_data = sfp; -#if SG_DEF_MERGE_FD - if (0 == sdp->merge_fd) - sdp->merge_fd = 1; -#endif - } else { if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */ return -ENOMEM; @@ -287,12 +309,10 @@ if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; 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_fasync(-1, filp, 0); /* remove filp from async notification list */ sg_remove_sfp(sdp, sfp); - if (! sdp->headfp) { + if (! sdp->headfp) filp->private_data = NULL; - sdp->merge_fd = 0; - } if (sdp->device->host->hostt->module) __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); @@ -311,70 +331,162 @@ Sg_fd * sfp; Sg_request * srp; int req_pack_id = -1; - struct sg_header * shp = (struct sg_header *)buf; + struct sg_header old_hdr; + sg_io_hdr_t new_hdr; + sg_io_hdr_t * hp; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", + SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", MINOR(sdp->i_rdev), (int)count)); - + if(! scsi_block_when_processing_errors(sdp->device)) return -ENXIO; if (ppos != &filp->f_pos) ; /* 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)) - req_pack_id = shp->pack_id; + if (sfp->force_packid && (count >= size_sg_header)) { + __copy_from_user(&old_hdr, buf, size_sg_header); + if (old_hdr.reply_len < 0) { + if (count >= size_sg_io_hdr) { + __copy_from_user(&new_hdr, buf, size_sg_io_hdr); + req_pack_id = new_hdr.pack_id; + } + } + else + req_pack_id = old_hdr.pack_id; + } srp = sg_get_request(sfp, req_pack_id); if (! srp) { /* now wait on packet to arrive */ if (filp->f_flags & O_NONBLOCK) return -EAGAIN; - res = 0; /* following is a macro that beats race condition */ - __wait_event_interruptible(sfp->read_wait, + 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_request(sfp, req_pack_id)), res); - if (res) - return res; /* -ERESTARTSYS because signal hit process */ + if (0 == res) + break; + else if (! dio) /* only let signal out if no dio */ + 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); + 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; + old_hdr.twelve_byte = + ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0; + old_hdr.target_status = hp->masked_status; + old_hdr.host_status = hp->host_status; + old_hdr.driver_status = hp->driver_status; + if ((CHECK_CONDITION & hp->masked_status) || + (DRIVER_SENSE & hp->driver_status)) + memcpy(old_hdr.sense_buffer, srp->sense_b, + sizeof(old_hdr.sense_buffer)); + switch (hp->host_status) + { /* This setup of 'result' is for backward compatibility and is best + ignored by the user who should use target, host + driver status */ + case DID_OK: + case DID_PASSTHROUGH: + case DID_SOFT_ERROR: + old_hdr.result = 0; + break; + case DID_NO_CONNECT: + case DID_BUS_BUSY: + case DID_TIME_OUT: + old_hdr.result = EBUSY; + break; + case DID_BAD_TARGET: + case DID_ABORT: + case DID_PARITY: + case DID_RESET: + case DID_BAD_INTR: + old_hdr.result = EIO; + break; + case DID_ERROR: + old_hdr.result = + (srp->sense_b[0] == 0 && hp->masked_status == GOOD) ? 0 : EIO; + break; + default: + old_hdr.result = EIO; + break; } - if (2 != sfp->underrun_flag) - srp->header.pack_len = srp->header.reply_len; /* Why ????? */ /* Now copy the result back to the user buffer. */ if (count >= size_sg_header) { - __copy_to_user(buf, &srp->header, size_sg_header); + __copy_to_user(buf, &old_hdr, size_sg_header); buf += size_sg_header; - if (count > srp->header.reply_len) - count = srp->header.reply_len; - if (count > size_sg_header) /* release does copy_to_user */ - sg_finish_rem_req(srp, buf, count - size_sg_header); - else - sg_finish_rem_req(srp, NULL, 0); + 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); } - else { - count = (srp->header.result == 0) ? 0 : -EIO; - sg_finish_rem_req(srp, NULL, 0); - } - if (! sfp->cmd_q) - wake_up_interruptible(&sfp->write_wait); + else + count = (old_hdr.result == 0) ? 0 : -EIO; + sg_finish_rem_req(srp); return count; } -static ssize_t sg_write(struct file * filp, const char * buf, +static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count, + Sg_request * srp) +{ + Sg_device * sdp = sfp->parentdp; + sg_io_hdr_t * hp = &srp->header; + int k, len; + + if(! scsi_block_when_processing_errors(sdp->device) ) + return -ENXIO; + if (count < size_sg_io_hdr) + return -EINVAL; + + hp->sb_len_wr = 0; + if ((hp->mx_sb_len > 0) && hp->sbp) { + if ((CHECK_CONDITION & hp->masked_status) || + (DRIVER_SENSE & hp->driver_status)) { + int sb_len = sizeof(dummy_cmdp->sense_buffer); + 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; + __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 */ + sg_finish_rem_req(srp); + return count; +} + + +static ssize_t sg_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) { int mxsize, cmd_size, k; - unsigned char cmnd[MAX_COMMAND_SIZE]; - int input_size; + int input_size, blocking; unsigned char opcode; - Scsi_Cmnd * SCpnt; Sg_device * sdp; Sg_fd * sfp; Sg_request * srp; + struct sg_header old_hdr; + sg_io_hdr_t * hp; + unsigned char cmnd[sizeof(dummy_cmdp->cmnd)]; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", + SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", MINOR(sdp->i_rdev), (int)count)); if(! scsi_block_when_processing_errors(sdp->device) ) @@ -384,33 +496,26 @@ if ((k = verify_area(VERIFY_READ, buf, count))) return k; /* protects following copy_from_user()s + get_user()s */ + if (count < size_sg_header) + return -EIO; + __copy_from_user(&old_hdr, buf, size_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)) - return -EIO; /* The minimum scsi command length is 6 bytes. */ + return -EIO; /* The minimum scsi command length is 6 bytes. */ if (! (srp = sg_add_request(sfp))) { - if (sfp->cmd_q) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n")); - return -EDOM; - } - else { /* old semantics: wait for pending read() to finish */ - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - k = 0; - __wait_event_interruptible(sfp->write_wait, - (srp = sg_add_request(sfp)), - k); - if (k) - return k; /* -ERESTARTSYS because signal hit process */ - } + SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n")); + return -EDOM; } - __copy_from_user(&srp->header, buf, size_sg_header); buf += size_sg_header; - srp->header.pack_len = count; __get_user(opcode, buf); if (sfp->next_cmd_len > 0) { if (sfp->next_cmd_len > MAX_COMMAND_SIZE) { SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n")); sfp->next_cmd_len = 0; + sg_remove_request(sfp, srp); return -EIO; } cmd_size = sfp->next_cmd_len; @@ -418,87 +523,204 @@ } else { cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */ - if ((opcode >= 0xc0) && srp->header.twelve_byte) + if ((opcode >= 0xc0) && old_hdr.twelve_byte) cmd_size = 12; } - SCSI_LOG_TIMEOUT(4, printk("sg_write: scsi opcode=0x%02x, cmd_size=%d\n", + SCSI_LOG_TIMEOUT(4, printk("sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int)opcode, cmd_size)); /* Determine buffer size. */ input_size = count - cmd_size; - mxsize = (input_size > srp->header.reply_len) ? input_size : - srp->header.reply_len; + mxsize = (input_size > old_hdr.reply_len) ? input_size : + old_hdr.reply_len; mxsize -= size_sg_header; input_size -= size_sg_header; if (input_size < 0) { sg_remove_request(sfp, srp); return -EIO; /* User did not pass enough bytes for this command. */ } - if ((k = sg_start_req(srp, mxsize, buf + cmd_size, input_size))) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: build err=%d\n", k)); - sg_finish_rem_req(srp, NULL, 0); + hp = &srp->header; + hp->interface_id = '\0'; /* indicator of old interface tunnelled */ + hp->cmd_len = (unsigned char)cmd_size; + hp->iovec_count = 0; + hp->mx_sb_len = 0; + if (input_size > 0) + hp->dxfer_direction = ((old_hdr.reply_len - size_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; + hp->dxfer_len = mxsize; + hp->dxferp = (unsigned char *)buf + cmd_size; + hp->sbp = NULL; + hp->timeout = old_hdr.reply_len; /* structure abuse ... */ + hp->flags = input_size; /* structure abuse ... */ + hp->pack_id = old_hdr.pack_id; + hp->usr_ptr = NULL; + __copy_from_user(cmnd, buf, cmd_size); + k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking); + return (k < 0) ? k : count; +} + +static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count, + int blocking, int read_only, Sg_request ** o_srp) +{ + int k; + Sg_request * srp; + sg_io_hdr_t * hp; + unsigned char cmnd[sizeof(dummy_cmdp->cmnd)]; + int timeout; + + if (count < size_sg_io_hdr) + return -EINVAL; + if ((k = verify_area(VERIFY_READ, buf, count))) + return k; /* protects following copy_from_user()s + get_user()s */ + + sfp->cmd_q = 1; /* when sg_io_hdr seen, set command queuing on */ + if (! (srp = sg_add_request(sfp))) { + SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n")); + return -EDOM; + } + hp = &srp->header; + __copy_from_user(hp, buf, size_sg_io_hdr); + if (hp->interface_id != 'S') { + sg_remove_request(sfp, srp); + return -ENOSYS; + } + timeout = sg_ms_to_jif(srp->header.timeout); + if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) { + sg_remove_request(sfp, srp); + return -EMSGSIZE; + } + if ((k = verify_area(VERIFY_READ, hp->cmdp, hp->cmd_len))) { + sg_remove_request(sfp, srp); + return k; /* protects following copy_from_user()s + get_user()s */ + } + __copy_from_user(cmnd, hp->cmdp, hp->cmd_len); + if (read_only && + (! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) { + sg_remove_request(sfp, srp); + return -EACCES; + } + k = sg_common_write(sfp, srp, cmnd, timeout, blocking); + if (k < 0) return k; + if (o_srp) *o_srp = srp; + return count; +} + +static int sg_common_write(Sg_fd * sfp, Sg_request * srp, + unsigned char * cmnd, int timeout, int blocking) +{ + int k; + Scsi_Cmnd * SCpnt; + Sg_device * sdp = sfp->parentdp; + sg_io_hdr_t * hp = &srp->header; + + srp->data.cmd_opcode = cmnd[0]; /* hold opcode of command */ + hp->status = 0; + hp->masked_status = 0; + hp->msg_status = 0; + hp->info = 0; + hp->host_status = 0; + hp->driver_status = 0; + hp->resid = 0; + SCSI_LOG_TIMEOUT(4, + printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", + (int)cmnd[0], (int)hp->cmd_len)); + + if ((k = sg_start_req(srp))) { + SCSI_LOG_TIMEOUT(1, printk("sg_write: start_req err=%d\n", k)); + sg_finish_rem_req(srp); return k; /* probably out of space --> ENOMEM */ } + if ((k = sg_write_xfer(srp))) { + SCSI_LOG_TIMEOUT(1, printk("sg_write: write_xfer, bad address\n")); + sg_finish_rem_req(srp); + return k; + } /* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */ - if (! (SCpnt = scsi_allocate_device(sdp->device, - !(filp->f_flags & O_NONBLOCK), - TRUE))) { - sg_finish_rem_req(srp, NULL, 0); - if( signal_pending(current) ) - { - return -EINTR; - } - return -EAGAIN; /* No available command blocks at the moment */ + SCpnt = scsi_allocate_device(sdp->device, blocking, TRUE); + if (! SCpnt) { + sg_finish_rem_req(srp); + return (signal_pending(current)) ? -EINTR : -EAGAIN; + /* No available command blocks, or, interrupted while waiting */ } /* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */ srp->my_cmdp = SCpnt; SCpnt->request.rq_dev = sdp->i_rdev; SCpnt->request.rq_status = RQ_ACTIVE; SCpnt->sense_buffer[0] = 0; - SCpnt->cmd_len = cmd_size; - __copy_from_user(cmnd, buf, cmd_size); + SCpnt->cmd_len = hp->cmd_len; /* Set the LUN field in the command structure, overriding user input */ - cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5); + 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")); */ - SCpnt->use_sg = srp->data.use_sg; + SCpnt->use_sg = srp->data.k_use_sg; SCpnt->sglist_len = srp->data.sglist_len; SCpnt->bufflen = srp->data.bufflen; - if (1 == sfp->underrun_flag) - SCpnt->underflow = srp->data.bufflen; - else - SCpnt->underflow = 0; + SCpnt->underflow = 0; SCpnt->buffer = srp->data.buffer; - srp->data.use_sg = 0; + srp->data.k_use_sg = 0; srp->data.sglist_len = 0; srp->data.bufflen = 0; srp->data.buffer = NULL; + hp->duration = jiffies; /* Now send everything of to mid-level. The next time we hear about this - packet is when sg_command_done() is called (ie a callback). */ + packet is when sg_cmd_done_bh() is called (i.e. a callback). */ scsi_do_cmd(SCpnt, (void *)cmnd, - (void *)SCpnt->buffer, mxsize, - sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES); - /* 'mxsize' overwrites SCpnt->bufflen, hence need for b_malloc_len */ -/* SCSI_LOG_TIMEOUT(6, printk("sg_write: sent scsi cmd to mid-level\n")); */ - return count; + (void *)SCpnt->buffer, hp->dxfer_len, + sg_cmd_done_bh, timeout, SG_DEFAULT_RETRIES); + /* dxfer_len overwrites SCpnt->bufflen, hence need for b_malloc_len */ + return 0; } static int sg_ioctl(struct inode * inode, struct file * filp, unsigned int cmd_in, unsigned long arg) { - int result, val; + int result, val, read_only; Sg_device * sdp; Sg_fd * sfp; Sg_request * srp; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", + SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", MINOR(sdp->i_rdev), (int)cmd_in)); if(! scsi_block_when_processing_errors(sdp->device) ) return -ENXIO; + read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); switch(cmd_in) { + case SG_IO: + { + int blocking = 1; /* ignore O_NONBLOCK flag */ + + if(! scsi_block_when_processing_errors(sdp->device) ) + return -ENXIO; + result = verify_area(VERIFY_WRITE, (void *)arg, size_sg_io_hdr); + if (result) return result; + result = sg_new_write(sfp, (const char *)arg, size_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); + 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 */ + } + } + result = sg_new_read(sfp, (char *)arg, size_sg_io_hdr, srp); + return (result < 0) ? result : 0; + } case SG_SET_TIMEOUT: result = get_user(val, (int *)arg); if (result) return result; @@ -525,21 +747,21 @@ case SG_GET_LOW_DMA: return put_user((int)sfp->low_dma, (int *)arg); case SG_GET_SCSI_ID: - result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(Sg_scsi_id)); + result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(sg_scsi_id_t)); if (result) return result; else { - Sg_scsi_id * sg_idp = (Sg_scsi_id *)arg; + sg_scsi_id_t * sg_idp = (sg_scsi_id_t *)arg; __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); __put_user((int)sdp->device->lun, &sg_idp->lun); __put_user((int)sdp->device->type, &sg_idp->scsi_type); - __put_user((short)sdp->device->host->cmd_per_lun, + __put_user((short)sdp->device->host->cmd_per_lun, &sg_idp->h_cmd_per_lun); - __put_user((short)sdp->device->queue_depth, + __put_user((short)sdp->device->queue_depth, &sg_idp->d_queue_depth); - __put_user(0, &sg_idp->unused1); - __put_user(0, &sg_idp->unused2); + __put_user(0, &sg_idp->unused[0]); + __put_user(0, &sg_idp->unused[1]); return 0; } case SG_SET_FORCE_PACK_ID: @@ -552,7 +774,7 @@ if (result) return result; srp = sfp->headrp; while (srp) { - if (! srp->my_cmdp) { + if (srp->done && (! srp->sg_io_owned)) { __put_user(srp->header.pack_id, (int *)arg); return 0; } @@ -564,7 +786,7 @@ srp = sfp->headrp; val = 0; while (srp) { - if (! srp->my_cmdp) + if (srp->done && (! srp->sg_io_owned)) ++val; srp = srp->nextrp; } @@ -572,8 +794,6 @@ case SG_GET_SG_TABLESIZE: return put_user(sdp->sg_tablesize, (int *)arg); case SG_SET_RESERVED_SIZE: - if (O_RDWR != (filp->f_flags & O_ACCMODE)) - return -EACCES; result = get_user(val, (int *)arg); if (result) return result; if (val != sfp->reserve.bufflen) { @@ -586,20 +806,6 @@ case SG_GET_RESERVED_SIZE: val = (int)sfp->reserve.bufflen; return put_user(val, (int *)arg); - case SG_GET_MERGE_FD: - return put_user((int)sdp->merge_fd, (int *)arg); - case SG_SET_MERGE_FD: - if (O_RDWR != (filp->f_flags & O_ACCMODE)) - return -EACCES; /* require write access since effect wider - then just this fd */ - result = get_user(val, (int *)arg); - if (result) return result; - val = val ? 1 : 0; - if ((val ^ (0 != sdp->merge_fd)) && - sdp->headfp && sdp->headfp->nextfp) - return -EBUSY; /* too much work if multiple fds already */ - sdp->merge_fd = val; - return 0; case SG_SET_COMMAND_Q: result = get_user(val, (int *)arg); if (result) return result; @@ -607,13 +813,13 @@ return 0; case SG_GET_COMMAND_Q: return put_user((int)sfp->cmd_q, (int *)arg); - case SG_SET_UNDERRUN_FLAG: + case SG_SET_KEEP_ORPHAN: result = get_user(val, (int *)arg); if (result) return result; - sfp->underrun_flag = val; + sfp->keep_orphan = val; return 0; - case SG_GET_UNDERRUN_FLAG: - return put_user((int)sfp->underrun_flag, (int *)arg); + case SG_GET_KEEP_ORPHAN: + return put_user((int)sfp->keep_orphan, (int *)arg); case SG_NEXT_CMD_LEN: result = get_user(val, (int *)arg); if (result) return result; @@ -621,6 +827,32 @@ return 0; case SG_GET_VERSION_NUM: 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); + if (result) return result; + else { + sg_req_info_t rinfo[SG_MAX_QUEUE]; + Sg_request * srp = sfp->headrp; + for (val = 0; val < SG_MAX_QUEUE; + ++val, srp = srp ? srp->nextrp : srp) { + memset(&rinfo[val], 0, size_sg_req_info); + if (srp) { + rinfo[val].req_state = srp->done ? 2 : 1; + rinfo[val].problem = srp->header.masked_status & + srp->header.host_status & srp->header.driver_status; + rinfo[val].duration = srp->done ? + sg_jif_to_ms(srp->header.duration) : + sg_jif_to_ms(jiffies - srp->header.duration); + rinfo[val].orphan = srp->orphan; + rinfo[val].sg_io_owned = srp->sg_io_owned; + rinfo[val].pack_id = srp->header.pack_id; + rinfo[val].usr_ptr = srp->header.usr_ptr; + } + } + __copy_to_user((void *)arg, rinfo, size_sg_req_info * SG_MAX_QUEUE); + return 0; + } case SG_EMULATED_HOST: return put_user(sdp->device->host->hostt->emulated, (int *)arg); case SG_SCSI_RESET: @@ -628,23 +860,22 @@ return -EBUSY; result = get_user(val, (int *)arg); if (result) return result; - /* Don't do anything till scsi mod level visibility */ + /* Don't do anything till scsi mid level visibility */ return 0; case SCSI_IOCTL_SEND_COMMAND: - /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the - user already has read/write access to the generic device and so - can execute arbitrary SCSI commands. */ - if (O_RDWR != (filp->f_flags & O_ACCMODE)) - return -EACCES; /* very dangerous things can be done here */ + if (read_only) { + unsigned char opcode = WRITE_6; + Scsi_Ioctl_Command * siocp = (void *)arg; + + copy_from_user(&opcode, siocp->data, 1); + if (! sg_allow_access(opcode, sdp->device->type)) + return -EACCES; + } return scsi_ioctl_send_command(sdp->device, (void *)arg); case SG_SET_DEBUG: result = get_user(val, (int *)arg); if (result) return result; sdp->sgdebug = (char)val; - if (9 == sdp->sgdebug) - sg_debug(sdp, sfp, 0); - else if (sdp->sgdebug > 9) - sg_debug_all(sfp); return 0; case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_GET_BUS_NUMBER: @@ -652,7 +883,7 @@ case SG_GET_TRANSFORM: return scsi_ioctl(sdp->device, cmd_in, (void *)arg); default: - if (O_RDWR != (filp->f_flags & O_ACCMODE)) + if (read_only) return -EACCES; /* don't know so take safe approach */ return scsi_ioctl(sdp->device, cmd_in, (void *)arg); } @@ -671,18 +902,18 @@ poll_wait(filp, &sfp->read_wait, wait); srp = sfp->headrp; while (srp) { /* if any read waiting, flag it */ - if (! (res || srp->my_cmdp)) + if ((0 == res) && srp->done && (! srp->sg_io_owned)) res = POLLIN | POLLRDNORM; ++count; srp = srp->nextrp; } - if (0 == sfp->cmd_q) { + if (! sfp->cmd_q) { if (0 == count) res |= POLLOUT | POLLWRNORM; } else if (count < SG_MAX_QUEUE) res |= POLLOUT | POLLWRNORM; - SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n", + SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n", MINOR(sdp->i_rdev), (int)res)); return res; } @@ -695,36 +926,29 @@ if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n", + SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n", MINOR(sdp->i_rdev), mode)); retval = fasync_helper(fd, filp, mode, &sfp->async_qp); return (retval < 0) ? retval : 0; } -/* This function is called by the interrupt handler when we - * actually have a command that is complete. */ -static void sg_command_done(Scsi_Cmnd * SCpnt) +/* This function is a "bottom half" handler that is called by the + * mid level when a command is completed (or has failed). */ +static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) { int dev = MINOR(SCpnt->request.rq_dev); Sg_device * sdp; Sg_fd * sfp; Sg_request * srp = NULL; - int closed = 0; - static const int min_sb_len = - SG_MAX_SENSE > sizeof(SCpnt->sense_buffer) ? - sizeof(SCpnt->sense_buffer) : SG_MAX_SENSE; - if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) { - SCSI_LOG_TIMEOUT(1, printk("sg__done: bad args dev=%d\n", dev)); + if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max) + || (NULL == (sdp = &sg_dev_arr[dev]))) { + SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; return; } - sdp = &sg_dev_arr[dev]; - if (NULL == sdp->device) - return; /* Get out of here quick ... */ - sfp = sdp->headfp; while (sfp) { srp = sfp->headrp; @@ -738,215 +962,88 @@ sfp = sfp->nextfp; } if (! srp) { - SCSI_LOG_TIMEOUT(1, printk("sg__done: req missing, dev=%d\n", dev)); + SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; return; } -/* First transfer ownership of data buffers to sg_device object. */ - srp->data.use_sg = SCpnt->use_sg; + /* First transfer ownership of data buffers to sg_device object. */ + srp->data.k_use_sg = SCpnt->use_sg; srp->data.sglist_len = SCpnt->sglist_len; srp->data.bufflen = SCpnt->bufflen; srp->data.buffer = SCpnt->buffer; - if (2 == sfp->underrun_flag) - srp->header.pack_len = SCpnt->underflow; sg_clr_scpnt(SCpnt); srp->my_cmdp = NULL; + srp->done = 1; - SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", - dev, (int)status_byte(SCpnt->result), (int)SCpnt->result)); - memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, min_sb_len); - switch (host_byte(SCpnt->result)) - { /* This setup of 'result' is for backward compatibility and is best - ignored by the user who should use target, host + driver status */ - case DID_OK: - case DID_PASSTHROUGH: - case DID_SOFT_ERROR: - srp->header.result = 0; - break; - case DID_NO_CONNECT: - case DID_BUS_BUSY: - case DID_TIME_OUT: - srp->header.result = EBUSY; - break; - case DID_BAD_TARGET: - case DID_ABORT: - case DID_PARITY: - case DID_RESET: - case DID_BAD_INTR: - srp->header.result = EIO; - break; - case DID_ERROR: - if (SCpnt->sense_buffer[0] == 0 && - status_byte(SCpnt->result) == GOOD) - srp->header.result = 0; - else - srp->header.result = EIO; - break; - default: - SCSI_LOG_TIMEOUT(1, printk( - "sg: unexpected host_byte=%d, dev=%d in 'done'\n", - host_byte(SCpnt->result), dev)); - srp->header.result = EIO; - break; - } - -/* Following if statement is a patch supplied by Eric Youngdale */ - if (driver_byte(SCpnt->result) != 0 - && (SCpnt->sense_buffer[0] & 0x7f) == 0x70 - && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION - && sdp->device->removable) { -/* Detected disc change. Set the bit - this may be used if there are */ -/* filesystems using this device. */ - sdp->device->changed = 1; - } - srp->header.target_status = status_byte(SCpnt->result); - if ((sdp->sgdebug > 0) && - ((CHECK_CONDITION == srp->header.target_status) || - (COMMAND_TERMINATED == srp->header.target_status))) - print_sense("sg_command_done", SCpnt); - srp->header.host_status = host_byte(SCpnt->result); - srp->header.driver_status = driver_byte(SCpnt->result); + SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n", + dev, srp->header.pack_id, (int)SCpnt->result)); + srp->header.resid = SCpnt->resid; + /* sg_unmap_and(&srp->data, 0); */ /* unmap locked pages a.s.a.p. */ + srp->header.duration = sg_jif_to_ms(jiffies - (int)srp->header.duration); + if (0 != SCpnt->result) { + memcpy(srp->sense_b, SCpnt->sense_buffer, sizeof(srp->sense_b)); + srp->header.status = 0xff & SCpnt->result; + srp->header.masked_status = status_byte(SCpnt->result); + srp->header.msg_status = msg_byte(SCpnt->result); + srp->header.host_status = host_byte(SCpnt->result); + srp->header.driver_status = driver_byte(SCpnt->result); + if ((sdp->sgdebug > 0) && + ((CHECK_CONDITION == srp->header.masked_status) || + (COMMAND_TERMINATED == srp->header.masked_status))) + print_sense("sg_cmd_done_bh", SCpnt); + + /* Following if statement is a patch supplied by Eric Youngdale */ + if (driver_byte(SCpnt->result) != 0 + && (SCpnt->sense_buffer[0] & 0x7f) == 0x70 + && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION + && sdp->device->removable) { + /* Detected disc change. Set the bit - this may be used if */ + /* there are filesystems using this device. */ + sdp->device->changed = 1; + } + } + /* Rely on write phase to clean out srp status values, so no "else" */ scsi_release_command(SCpnt); SCpnt = NULL; if (sfp->closed) { /* whoops this fd already released, cleanup */ - closed = 1; SCSI_LOG_TIMEOUT(1, - printk("sg__done: already closed, freeing ...\n")); -/* should check if module is unloaded <<<<<<< */ - sg_finish_rem_req(srp, NULL, 0); - if (NULL == sfp->headrp) { + printk("sg...bh: already closed, freeing ...\n")); + /* should check if module is unloaded <<<<<<< */ + sg_finish_rem_req(srp); + srp = NULL; + if (NULL == sfp->headrp) { SCSI_LOG_TIMEOUT(1, - printk("sg__done: already closed, final cleanup\n")); + printk("sg...bh: already closed, final cleanup\n")); sg_remove_sfp(sdp, sfp); + sfp = NULL; } } -/* Now wake up any sg_read() that is waiting for this packet. */ - wake_up_interruptible(&sfp->read_wait); - if ((sfp->async_qp) && (! closed)) - kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN); -} - -static void sg_debug_all(const Sg_fd * sfp) -{ - const Sg_device * sdp = sg_dev_arr; - int k; - - if (NULL == sg_dev_arr) { - printk("sg_debug_all: sg_dev_arr NULL, death is imminent\n"); - return; - } - if (! sfp) - printk("sg_debug_all: sfp (file descriptor pointer) NULL\n"); - - printk("sg_debug_all: dev_max=%d, %s\n", - sg_template.dev_max, sg_version_str); - printk(" scsi_dma_free_sectors=%u, sg_pool_secs_aval=%d\n", - scsi_dma_free_sectors, sg_pool_secs_avail); - printk(" sg_big_buff=%d\n", sg_big_buff); -#ifdef SG_DEBUG - printk(" malloc counts, kmallocs=%d, dma_pool=%d, pages=%d\n", - sg_num_kmal, sg_num_pool, sg_num_page); -#endif - for (k = 0; k < sg_template.dev_max; ++k, ++sdp) { - if (sdp->headfp) { - if (! sfp) - sfp = sdp->headfp; /* just to keep things going */ - else if (sdp == sfp->parentdp) - printk(" ***** Invoking device follows *****\n"); - sg_debug(sdp, sfp, 1); - } - } -} - -static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of) -{ - Sg_fd * fp; - Sg_request * srp; - int dev; - int k; - - if (! sfp) - printk("sg_debug: sfp (file descriptor pointer) NULL\n"); - if (! sdp) { - printk("sg_debug: sdp pointer (to device) NULL\n"); - return; - } - else if (! sdp->device) { - printk("sg_debug: device detached ??\n"); - return; - } - dev = MINOR(sdp->i_rdev); - - if (part_of) - printk(" >>> device=%d(sg%c), ", dev, 'a' + dev); - else - printk("sg_debug: device=%d(sg%c), ", dev, 'a' + dev); - printk("scsi%d chan=%d id=%d lun=%d em=%d\n", sdp->device->host->host_no, - sdp->device->channel, sdp->device->id, sdp->device->lun, - sdp->device->host->hostt->emulated); - printk(" sg_tablesize=%d, excl=%d, sgdebug=%d, merge_fd=%d\n", - sdp->sg_tablesize, sdp->exclude, sdp->sgdebug, sdp->merge_fd); - if (! part_of) { - printk(" scsi_dma_free_sectors=%u, sg_pool_secs_aval=%d\n", - scsi_dma_free_sectors, sg_pool_secs_avail); -#ifdef SG_DEBUG - printk(" mallocs: kmallocs=%d, dma_pool=%d, pages=%d\n", - sg_num_kmal, sg_num_pool, sg_num_page); -#endif - } - - fp = sdp->headfp; - for (k = 1; fp; fp = fp->nextfp, ++k) { - if (sfp == fp) - printk(" *** Following data belongs to invoking FD ***\n"); - else if (! fp->parentdp) - printk(">> Following FD has NULL parent pointer ???\n"); - printk(" FD(%d): timeout=%d, bufflen=%d, use_sg=%d\n", - k, fp->timeout, fp->reserve.bufflen, (int)fp->reserve.use_sg); - printk(" low_dma=%d, cmd_q=%d, s_sc_len=%d, f_packid=%d\n", - (int)fp->low_dma, (int)fp->cmd_q, (int)fp->save_scat_len, - (int)fp->force_packid); - printk(" urun_flag=%d, next_cmd_len=%d, closed=%d\n", - (int)fp->underrun_flag, (int)fp->next_cmd_len, - (int)fp->closed); - srp = fp->headrp; - if (NULL == srp) - printk(" No requests active\n"); - while (srp) { - if (srp->res_used) - printk("reserved buff >> "); - else - printk(" "); - if (srp->my_cmdp) - printk("written: pack_id=%d, bufflen=%d, use_sg=%d\n", - srp->header.pack_id, srp->my_cmdp->bufflen, - srp->my_cmdp->use_sg); - else - printk("to_read: pack_id=%d, bufflen=%d, use_sg=%d\n", - srp->header.pack_id, srp->data.bufflen, srp->data.use_sg); - if (! srp->parentfp) - printk(">> request has NULL parent pointer ???\n"); - srp = srp->nextrp; - } + else if (srp && srp->orphan) { + if (sfp->keep_orphan) + srp->sg_io_owned = 0; + else { + sg_finish_rem_req(srp); + srp = NULL; + } + } + if (sfp && srp) { + /* Now wake up any sg_read() that is waiting for this packet. */ + wake_up_interruptible(&sfp->read_wait); + if (sfp->async_qp) + kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN); } } static struct file_operations sg_fops = { - NULL, /* lseek */ - sg_read, /* read */ - sg_write, /* write */ - NULL, /* readdir */ - sg_poll, /* poll */ - sg_ioctl, /* ioctl */ - NULL, /* mmap */ - sg_open, /* open */ - NULL, /* flush */ - sg_release, /* release, was formerly sg_close */ - NULL, /* fsync */ - sg_fasync, /* fasync */ - NULL, /* lock */ + read: sg_read, + write: sg_write, + poll: sg_poll, + ioctl: sg_ioctl, + open: sg_open, + release: sg_release, + fasync: sg_fasync, }; @@ -962,7 +1059,7 @@ printk("Detected scsi generic sg%c at scsi%d," " channel %d, id %d, lun %d\n", 'a'+sg_template.dev_noticed, - scsidp->host->host_no, scsidp->channel, + scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun); } sg_template.dev_noticed++; @@ -973,6 +1070,7 @@ static int sg_init() { static int sg_registered = 0; + int size; if (sg_template.dev_noticed == 0) return 0; @@ -990,19 +1088,42 @@ if(sg_dev_arr) return 0; SCSI_LOG_TIMEOUT(3, printk("sg_init\n")); - sg_dev_arr = (Sg_device *) - kmalloc((sg_template.dev_noticed + SG_EXTRA_DEVS) - * sizeof(Sg_device), GFP_ATOMIC); - memset(sg_dev_arr, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS) - * sizeof(Sg_device)); + size = sizeof(Sg_device) * + (sg_template.dev_noticed + SG_EXTRA_DEVS); + sg_dev_arr = (Sg_device *)kmalloc(size, GFP_ATOMIC); + memset(sg_dev_arr, 0, size); if (NULL == sg_dev_arr) { printk("sg_init: no space for sg_dev_arr\n"); return 1; } +#ifdef CONFIG_PROC_FS + sg_proc_init(); +#endif /* CONFIG_PROC_FS */ sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS; return 0; } +#ifndef MODULE +static int __init sg_def_reserved_size_setup(char *str) +{ + int tmp; + + if (get_option(&str, &tmp) == 1) { + def_reserved_size = tmp; + if (tmp >= 0) + sg_big_buff = tmp; + return 1; + } else { + printk("sg_def_reserved_size : usage sg_def_reserved_size=n " + "(n could be 65536, 131072 or 262144)\n"); + return 0; + } +} + +__setup("sg_def_reserved_size=", sg_def_reserved_size_setup); +#endif + + static int sg_attach(Scsi_Device * scsidp) { Sg_device * sdp = sg_dev_arr; @@ -1011,6 +1132,8 @@ if ((sg_template.nr_dev >= sg_template.dev_max) || (! sdp)) { scsidp->attached--; + printk("sg_attach: rejected since exceeds dev_max=%d\n", + sg_template.dev_max); return 1; } @@ -1024,7 +1147,6 @@ init_waitqueue_head(&sdp->o_excl_wait); sdp->headfp= NULL; sdp->exclude = 0; - sdp->merge_fd = 0; /* Cope with SG_DEF_MERGE_FD on open */ sdp->sgdebug = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k); @@ -1052,13 +1174,13 @@ if(sdp->device != scsidp) continue; /* dirty but lowers nesting */ if (sdp->headfp) { -/* Need to stop sg_command_done() playing with this list during this loop */ +/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ spin_lock_irqsave(&sg_request_lock, flags); sfp = sdp->headfp; while (sfp) { srp = sfp->headrp; while (srp) { - if (srp->my_cmdp) + if (! srp->done) sg_shorten_timeout(srp->my_cmdp); srp = srp->nextrp; } @@ -1070,7 +1192,7 @@ } else { SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); - sdp->device = NULL; + sdp->device = NULL; } scsidp->attached--; sg_template.nr_dev--; @@ -1084,7 +1206,12 @@ #ifdef MODULE +MODULE_PARM(def_reserved_size, "i"); +MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); + int init_module(void) { + if (def_reserved_size >= 0) + sg_big_buff = def_reserved_size; sg_template.module = &__this_module; return scsi_register_module(MODULE_SCSI_DEV, &sg_template); } @@ -1094,10 +1221,13 @@ scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); +#ifdef CONFIG_PROC_FS + sg_proc_cleanup(); +#endif /* CONFIG_PROC_FS */ 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); + kfree((char *)sg_dev_arr); sg_dev_arr = NULL; } sg_template.dev_max = 0; @@ -1124,56 +1254,178 @@ scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_old_times_out); #else - spin_unlock_irq(&sg_request_lock); + unsigned long flags = 0; + spin_lock_irqsave(&sg_request_lock, flags); scsi_sleep(HZ); /* just sleep 1 second and hope ... */ - spin_lock_irq(&sg_request_lock); + spin_unlock_irqrestore(&sg_request_lock, flags); #endif } -static int sg_start_req(Sg_request * srp, int max_buff_size, - const char * inp, int num_write_xfer) +static int sg_start_req(Sg_request * srp) { int res; Sg_fd * sfp = srp->parentfp; + sg_io_hdr_t * hp = &srp->header; + int dxfer_len = (int)hp->dxfer_len; Sg_scatter_hold * req_schp = &srp->data; Sg_scatter_hold * rsv_schp = &sfp->reserve; - SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n", - max_buff_size)); - if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) { - sg_link_reserve(sfp, srp, max_buff_size); - sg_write_xfer(req_schp, inp, num_write_xfer); + SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len)); + if ((hp->flags & SG_FLAG_DIRECT_IO) && (dxfer_len > 0) && + (hp->dxfer_direction != SG_DXFER_NONE) && (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 */ + return res; + } + if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) { + sg_link_reserve(sfp, srp, dxfer_len); } else { - res = sg_build_scat(req_schp, max_buff_size, sfp); + res = sg_build_indi(req_schp, sfp, dxfer_len); if (res) { sg_remove_scat(req_schp); return res; } - sg_write_xfer(req_schp, inp, num_write_xfer); } return 0; } -static void sg_finish_rem_req(Sg_request * srp, char * outp, - int num_read_xfer) +static void sg_finish_rem_req(Sg_request * srp) { Sg_fd * sfp = srp->parentfp; Sg_scatter_hold * req_schp = &srp->data; SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", - (int)srp->res_used)); - if (num_read_xfer > 0) - sg_read_xfer(req_schp, outp, num_read_xfer); + (int)srp->res_used)); + sg_unmap_and(&srp->data, 1); if (srp->res_used) sg_unlink_reserve(sfp, srp); - else + else sg_remove_scat(req_schp); sg_remove_request(sfp, srp); } -static int sg_build_scat(Sg_scatter_hold * schp, int buff_size, - const Sg_fd * sfp) +static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp) +{ + int mem_src, ret_sz; + int sg_bufflen = PAGE_SIZE; + int elem_sz = sizeof(struct scatterlist) + sizeof(char); + int mx_sc_elems = (sg_bufflen / elem_sz) - 1; + + mem_src = SG_HEAP_KMAL; + schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen, + &ret_sz, &mem_src); + schp->buffer_mem_src = (char)mem_src; + if (! schp->buffer) + return -ENOMEM; + else if (ret_sz != sg_bufflen) { + sg_bufflen = ret_sz; + mx_sc_elems = (sg_bufflen / elem_sz) - 1; + } + schp->sglist_len = sg_bufflen; + memset(schp->buffer, 0, sg_bufflen); + return mx_sc_elems; /* number of scat_gath elements allocated */ +} + +static void sg_unmap_and(Sg_scatter_hold * schp, int free_also) +{ +#ifdef SG_ALLOW_DIO + if (schp && schp->kiobp) { + if (schp->mapped) { + unmap_kiobuf(schp->kiobp); + schp->mapped = 0; + } + if (free_also) { + free_kiovec(1, &schp->kiobp); + schp->kiobp = NULL; + } + } +#endif +} + +static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len) +{ +#ifdef SG_ALLOW_DIO + int res, k, split, offset, num, mx_sc_elems, rem_sz; + struct kiobuf * kp; + char * mem_src_arr; + struct scatterlist * sclp; + unsigned long addr, prev_addr; + sg_io_hdr_t * hp = &srp->header; + Sg_scatter_hold * schp = &srp->data; + int sg_tablesize = sfp->parentdp->sg_tablesize; + + res = alloc_kiovec(1, &schp->kiobp); + if (0 != res) { + SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res)); + return 1; + } + res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0, + schp->kiobp, (unsigned long)hp->dxferp, dxfer_len); + if (0 != res) { + SCSI_LOG_TIMEOUT(5, + printk("sg_build_dir: map_user_kiobuf res=%d\n", res)); + sg_unmap_and(schp, 1); + return 1; + } + schp->mapped = 1; + kp = schp->kiobp; + prev_addr = page_address(kp->maplist[0]); + for (k = 1, split = 0; k < kp->nr_pages; ++k, prev_addr = addr) { + addr = page_address(kp->maplist[k]); + if ((prev_addr + PAGE_SIZE) != addr) { + split = k; + break; + } + } + if (! split) { + schp->k_use_sg = 0; + schp->buffer = (void *)(page_address(kp->maplist[0]) + kp->offset); + schp->bufflen = dxfer_len; + schp->buffer_mem_src = SG_USER_MEM; + schp->b_malloc_len = dxfer_len; + hp->info |= SG_INFO_DIRECT_IO; + return 0; + } + mx_sc_elems = sg_build_sgat(schp, sfp); + if (mx_sc_elems <= 1) { + sg_unmap_and(schp, 1); + sg_remove_scat(schp); + return 1; + } + mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist)); + for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len; + (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); + ++k, ++sclp) { + offset = (0 == k) ? kp->offset : 0; + num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) : + rem_sz; + sclp->address = (void *)(page_address(kp->maplist[k]) + offset); + sclp->length = num; + mem_src_arr[k] = SG_USER_MEM; + rem_sz -= num; + SCSI_LOG_TIMEOUT(5, + printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n", + k, sclp->address, num, mem_src_arr[k])); + } + schp->k_use_sg = k; + SCSI_LOG_TIMEOUT(5, + printk("sg_build_dir: k_use_sg=%d, rem_sz=%d\n", k, rem_sz)); + schp->bufflen = dxfer_len; + if (rem_sz > 0) { /* must have failed */ + sg_unmap_and(schp, 1); + sg_remove_scat(schp); + return 1; /* out of scatter gather elements, try indirect */ + } + hp->info |= SG_INFO_DIRECT_IO; + return 0; +#else + return 1; +#endif /* SG_ALLOW_DIO */ +} + +static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) { int ret_sz, mem_src; int blk_size = buff_size; @@ -1185,7 +1437,7 @@ ++blk_size; /* don't know why */ /* round request up to next highest SG_SECTOR_SZ byte boundary */ blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK); - SCSI_LOG_TIMEOUT(4, printk("sg_build_scat: buff_size=%d, blk_size=%d\n", + SCSI_LOG_TIMEOUT(4, printk("sg_build_indi: buff_size=%d, blk_size=%d\n", buff_size, blk_size)); if (blk_size <= SG_SCATTER_SZ) { mem_src = SG_HEAP_PAGE; @@ -1193,10 +1445,10 @@ if (! p) return -ENOMEM; if (blk_size == ret_sz) { /* got it on the first attempt */ - schp->use_sg = 0; + schp->k_use_sg = 0; schp->buffer = p; schp->bufflen = blk_size; - schp->mem_src = mem_src; + schp->buffer_mem_src = (char)mem_src; schp->b_malloc_len = blk_size; return 0; } @@ -1210,29 +1462,23 @@ /* Want some local declarations, so start new block ... */ { /* lets try and build a scatter gather list */ struct scatterlist * sclp; - int k, rem_sz, num, nxt; - int sc_bufflen = PAGE_SIZE; - int mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1; + int k, rem_sz, num; + int mx_sc_elems; int sg_tablesize = sfp->parentdp->sg_tablesize; int first = 1; + char * mem_src_arr; - k = SG_HEAP_KMAL; /* want to protect mem_src, use k as scratch */ - schp->buffer = (struct scatterlist *)sg_malloc(sfp, - sc_bufflen, &num, &k); - schp->mem_src = (char)k; /* N.B. ret_sz and mem_src carried into this block ... */ - if (! schp->buffer) - return -ENOMEM; - else if (num != sc_bufflen) { - sc_bufflen = num; - mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1; - } - schp->sglist_len = sc_bufflen; - memset(schp->buffer, 0, sc_bufflen); - for (k = 0, sclp = schp->buffer, rem_sz = blk_size, nxt =0; - (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); + mx_sc_elems = sg_build_sgat(schp, sfp); + if (mx_sc_elems < 0) + return mx_sc_elems; /* most likely -ENOMEM */ + mem_src_arr = schp->buffer + + (mx_sc_elems * sizeof(struct scatterlist)); + + for (k = 0, sclp = schp->buffer, rem_sz = blk_size; + (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); ++k, rem_sz -= ret_sz, ++sclp) { - if (first) + if (first) first = 0; else { num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz; @@ -1243,15 +1489,15 @@ } sclp->address = p; sclp->length = ret_sz; - sclp->alt_address = (char *)(long)mem_src; - - SCSI_LOG_TIMEOUT(5, - printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n", + mem_src_arr[k] = mem_src; + + SCSI_LOG_TIMEOUT(5, + printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n", k, sclp->address, ret_sz, mem_src)); } /* end of for loop */ - schp->use_sg = k; - SCSI_LOG_TIMEOUT(5, - printk("sg_build_scat: use_sg=%d, rem_sz=%d\n", k, rem_sz)); + schp->k_use_sg = k; + SCSI_LOG_TIMEOUT(5, + printk("sg_build_indi: k_use_sg=%d, rem_sz=%d\n", k, rem_sz)); schp->bufflen = blk_size; if (rem_sz > 0) /* must have failed */ return -ENOMEM; @@ -1259,74 +1505,254 @@ return 0; } -static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp, - int num_write_xfer) +static int sg_write_xfer(Sg_request * srp) { - SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_write_xfer=%d, use_sg=%d\n", - num_write_xfer, schp->use_sg)); - if ((! inp) || (num_write_xfer <= 0)) - return; - if (schp->use_sg > 0) { - int k, num; - struct scatterlist * sclp = (struct scatterlist *)schp->buffer; + sg_io_hdr_t * hp = &srp->header; + Sg_scatter_hold * schp = &srp->data; + int num_xfer = 0; + int j, k, onum, usglen, ksglen, res, ok; + int iovec_count = (int)hp->iovec_count; + unsigned char * p; + unsigned char * up; + int new_interface = ('\0' == hp->interface_id) ? 0 : 1; + + if ((SG_DXFER_TO_DEV == hp->dxfer_direction) || + (SG_DXFER_TO_FROM_DEV == hp->dxfer_direction)) { + num_xfer = (int)(new_interface ? hp->dxfer_len : hp->flags); + if (schp->bufflen < num_xfer) + num_xfer = schp->bufflen; + } + if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags))) + return 0; + + SCSI_LOG_TIMEOUT(4, + printk("sg_write_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n", + num_xfer, iovec_count, schp->k_use_sg)); + if (iovec_count) { + onum = iovec_count; + if ((k = verify_area(VERIFY_READ, hp->dxferp, + size_sg_iovec * onum))) + return k; + } + else + onum = 1; - for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) { - num = (int)sclp->length; - if (num > num_write_xfer) { - __copy_from_user(sclp->address, inp, num_write_xfer); - break; + if (0 == schp->k_use_sg) { /* kernel has single buffer */ + if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */ + + for (j = 0, p = schp->buffer; j < onum; ++j) { + res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up); + if (res) return res; + usglen = (num_xfer > usglen) ? usglen : num_xfer; + __copy_from_user(p, up, usglen); + p += usglen; + num_xfer -= usglen; + if (num_xfer <= 0) + return 0; } - else { - __copy_from_user(sclp->address, inp, num); - num_write_xfer -= num; - if (num_write_xfer <= 0) + } + } + else { /* kernel using scatter gather list */ + struct scatterlist * sclp = (struct scatterlist *)schp->buffer; + char * mem_src_arr = sg_get_sgat_msa(schp); + ksglen = (int)sclp->length; + p = sclp->address; + + for (j = 0, k = 0; j < onum; ++j) { + res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up); + if (res) return res; + + for (; (k < schp->k_use_sg) && p; + ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) { + ok = (SG_USER_MEM != mem_src_arr[k]); + if (usglen <= 0) + break; + if (ksglen > usglen) { + if (usglen >= num_xfer) { + if (ok) __copy_from_user(p, up, num_xfer); + return 0; + } + if (ok) __copy_from_user(p, up, usglen); + p += usglen; + ksglen -= usglen; break; - inp += num; + } + else { + if (ksglen >= num_xfer) { + if (ok) __copy_from_user(p, up, num_xfer); + return 0; + } + if (ok) __copy_from_user(p, up, ksglen); + up += ksglen; + usglen -= ksglen; + } } } } - else - __copy_from_user(schp->buffer, inp, num_write_xfer); + return 0; +} + +static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind, + int wr_xf, int * countp, unsigned char ** up) +{ + int num_xfer = (int)hp->dxfer_len; + unsigned char * p; + int count, k; + sg_iovec_t u_iovec; + + if (0 == sg_num) { + p = (unsigned char *)hp->dxferp; + if (wr_xf && ('\0' == hp->interface_id)) + count = (int)hp->flags; /* holds "old" input_size */ + else + count = num_xfer; + } + else { + __copy_from_user(&u_iovec, + (unsigned char *)hp->dxferp + (ind * size_sg_iovec), + size_sg_iovec); + p = (unsigned char *)u_iovec.iov_base; + count = (int)u_iovec.iov_len; + } + if ((k = verify_area(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count))) + return k; + if (up) *up = p; + if (countp) *countp = count; + return 0; +} + +static char * sg_get_sgat_msa(Sg_scatter_hold * schp) +{ + int elem_sz = sizeof(struct scatterlist) + sizeof(char); + int mx_sc_elems = (schp->sglist_len / elem_sz) - 1; + return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems); } static void sg_remove_scat(Sg_scatter_hold * schp) { - SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: use_sg=%d\n", schp->use_sg)); - if(schp->use_sg > 0) { + SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n", + schp->k_use_sg)); + if (schp->buffer && schp->sglist_len) { int k, mem_src; struct scatterlist * sclp = (struct scatterlist *)schp->buffer; + char * mem_src_arr = sg_get_sgat_msa(schp); - for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) { - mem_src = (int)(long)sclp->alt_address; - SCSI_LOG_TIMEOUT(5, - printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n", + for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) { + mem_src = mem_src_arr[k]; + SCSI_LOG_TIMEOUT(5, + printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n", k, sclp->address, sclp->length, mem_src)); sg_free(sclp->address, sclp->length, mem_src); sclp->address = NULL; sclp->length = 0; } - sg_free(schp->buffer, schp->sglist_len, schp->mem_src); + sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src); } else if (schp->buffer) - sg_free(schp->buffer, schp->b_malloc_len, schp->mem_src); - schp->buffer = NULL; - schp->bufflen = 0; - schp->use_sg = 0; - schp->sglist_len = 0; + sg_free(schp->buffer, schp->b_malloc_len, schp->buffer_mem_src); + memset(schp, 0, sizeof(*schp)); +} + +static int sg_read_xfer(Sg_request * srp) +{ + sg_io_hdr_t * hp = &srp->header; + Sg_scatter_hold * schp = &srp->data; + int num_xfer = 0; + int j, k, onum, usglen, ksglen, res, ok; + int iovec_count = (int)hp->iovec_count; + unsigned char * p; + unsigned char * up; + int new_interface = ('\0' == hp->interface_id) ? 0 : 1; + + if ((SG_DXFER_FROM_DEV == hp->dxfer_direction) || + (SG_DXFER_TO_FROM_DEV == hp->dxfer_direction)) { + num_xfer = hp->dxfer_len; + if (schp->bufflen < num_xfer) + num_xfer = schp->bufflen; + } + if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags))) + return 0; + + SCSI_LOG_TIMEOUT(4, + printk("sg_read_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n", + num_xfer, iovec_count, schp->k_use_sg)); + if (iovec_count) { + onum = iovec_count; + if ((k = verify_area(VERIFY_READ, hp->dxferp, + size_sg_iovec * onum))) + return k; + } + else + onum = 1; + + if (0 == schp->k_use_sg) { /* kernel has single buffer */ + if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */ + + for (j = 0, p = schp->buffer; j < onum; ++j) { + res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up); + if (res) return res; + usglen = (num_xfer > usglen) ? usglen : num_xfer; + __copy_to_user(up, p, usglen); + p += usglen; + num_xfer -= usglen; + if (num_xfer <= 0) + return 0; + } + } + } + else { /* kernel using scatter gather list */ + struct scatterlist * sclp = (struct scatterlist *)schp->buffer; + char * mem_src_arr = sg_get_sgat_msa(schp); + ksglen = (int)sclp->length; + p = sclp->address; + + for (j = 0, k = 0; j < onum; ++j) { + res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up); + if (res) return res; + + for (; (k < schp->k_use_sg) && p; + ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) { + ok = (SG_USER_MEM != mem_src_arr[k]); + if (usglen <= 0) + break; + if (ksglen > usglen) { + if (usglen >= num_xfer) { + if (ok) __copy_to_user(up, p, num_xfer); + return 0; + } + if (ok) __copy_to_user(up, p, usglen); + p += usglen; + ksglen -= usglen; + break; + } + else { + if (ksglen >= num_xfer) { + if (ok) __copy_to_user(up, p, num_xfer); + return 0; + } + if (ok) __copy_to_user(up, p, ksglen); + up += ksglen; + usglen -= ksglen; + } + } + } + } + return 0; } -static void sg_read_xfer(Sg_scatter_hold * schp, char * outp, - int num_read_xfer) +static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer) { - SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_read_xfer=%d\n", - num_read_xfer)); + Sg_scatter_hold * schp = &srp->data; + + SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n", + num_read_xfer)); if ((! outp) || (num_read_xfer <= 0)) return; - if(schp->use_sg > 0) { + if(schp->k_use_sg > 0) { int k, num; struct scatterlist * sclp = (struct scatterlist *)schp->buffer; - for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) { + for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) { num = (int)sclp->length; if (num > num_read_xfer) { __copy_to_user(outp, sclp->address, num_read_xfer); @@ -1349,11 +1775,11 @@ { Sg_scatter_hold * schp = &sfp->reserve; - SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size)); + SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size)); do { if (req_size < PAGE_SIZE) req_size = PAGE_SIZE; - if (0 == sg_build_scat(schp, req_size, sfp)) + if (0 == sg_build_indi(schp, sfp, req_size)) return; else sg_remove_scat(schp); @@ -1366,13 +1792,13 @@ Sg_scatter_hold * req_schp = &srp->data; Sg_scatter_hold * rsv_schp = &sfp->reserve; - SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); - if (rsv_schp->use_sg > 0) { + SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); + if (rsv_schp->k_use_sg > 0) { int k, num; int rem = size; struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer; - for (k = 0; k < rsv_schp->use_sg; ++k, ++sclp) { + for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) { num = (int)sclp->length; if (rem <= num) { sfp->save_scat_len = num; @@ -1382,23 +1808,23 @@ else rem -= num; } - if (k < rsv_schp->use_sg) { - req_schp->use_sg = k + 1; /* adjust scatter list length */ + if (k < rsv_schp->k_use_sg) { + req_schp->k_use_sg = k + 1; /* adjust scatter list length */ req_schp->bufflen = size; req_schp->sglist_len = rsv_schp->sglist_len; req_schp->buffer = rsv_schp->buffer; - req_schp->mem_src = rsv_schp->mem_src; + req_schp->buffer_mem_src = rsv_schp->buffer_mem_src; req_schp->b_malloc_len = rsv_schp->b_malloc_len; } else - SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n")); + SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n")); } else { - req_schp->use_sg = 0; + req_schp->k_use_sg = 0; req_schp->bufflen = size; req_schp->buffer = rsv_schp->buffer; - req_schp->mem_src = rsv_schp->mem_src; - req_schp->use_sg = rsv_schp->use_sg; + req_schp->buffer_mem_src = rsv_schp->buffer_mem_src; + req_schp->k_use_sg = rsv_schp->k_use_sg; req_schp->b_malloc_len = rsv_schp->b_malloc_len; } srp->res_used = 1; @@ -1409,19 +1835,19 @@ Sg_scatter_hold * req_schp = &srp->data; Sg_scatter_hold * rsv_schp = &sfp->reserve; - SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->use_sg=%d\n", - (int)req_schp->use_sg)); - if (rsv_schp->use_sg > 0) { + SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n", + (int)req_schp->k_use_sg)); + if (rsv_schp->k_use_sg > 0) { struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer; - if (sfp->save_scat_len > 0) - (sclp + (req_schp->use_sg - 1))->length = + if (sfp->save_scat_len > 0) + (sclp + (req_schp->k_use_sg - 1))->length = (unsigned)sfp->save_scat_len; else SCSI_LOG_TIMEOUT(1, printk( - "sg_unlink_reserve: BAD save_scat_len\n")); + "sg_unlink_reserve: BAD save_scat_len\n")); } - req_schp->use_sg = 0; + req_schp->k_use_sg = 0; req_schp->bufflen = 0; req_schp->buffer = NULL; req_schp->sglist_len = 0; @@ -1434,8 +1860,8 @@ Sg_request * resp = NULL; resp = sfp->headrp; - while (resp) { - if ((! resp->my_cmdp) && + while (resp) { /* look for requests that are ready + not SG_IO owned */ + if (resp->done && (! resp->sg_io_owned) && ((-1 == pack_id) || (resp->header.pack_id == pack_id))) return resp; resp = resp->nextrp; @@ -1477,15 +1903,21 @@ resp->parentfp = sfp; resp->nextrp = NULL; resp->res_used = 0; + resp->orphan = 0; + resp->sg_io_owned = 0; + resp->done = 0; memset(&resp->data, 0, sizeof(Sg_scatter_hold)); - memset(&resp->header, 0, sizeof(struct sg_header)); + memset(&resp->header, 0, size_sg_io_hdr); + resp->header.duration = jiffies; resp->my_cmdp = NULL; + resp->data.kiobp = NULL; + resp->data.mapped = 0; } return resp; } /* Return of 1 for found; 0 for not found */ -static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp) +static int sg_remove_request(Sg_fd * sfp, Sg_request * srp) { Sg_request * prev_rp; Sg_request * rp; @@ -1509,30 +1941,23 @@ return 0; } -static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved) +static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) { Sg_fd * sfp; - if (sdp->merge_fd) { - ++sdp->merge_fd; - return sdp->headfp; - } sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0); - if (sfp) { - memset(sfp, 0, sizeof(Sg_fd)); - sfp->my_mem_src = SG_HEAP_KMAL; - init_waitqueue_head(&sfp->read_wait); - init_waitqueue_head(&sfp->write_wait); - } - else + if (! sfp) return NULL; - + memset(sfp, 0, sizeof(Sg_fd)); + sfp->fd_mem_src = SG_HEAP_KMAL; + init_waitqueue_head(&sfp->read_wait); + sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->force_packid = SG_DEF_FORCE_PACK_ID; sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? sdp->device->host->unchecked_isa_dma : 1; sfp->cmd_q = SG_DEF_COMMAND_Q; - sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG; + sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; sfp->parentdp = sdp; if (! sdp->headfp) sdp->headfp = sfp; @@ -1543,13 +1968,10 @@ pfp->nextfp = sfp; } SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n", - sfp, (int)sfp->my_mem_src)); - if (get_reserved) { - sg_build_reserve(sfp, SG_DEF_RESERVED_SIZE); - sg_big_buff = sfp->reserve.bufflen; /* sysctl shows most recent size */ - SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, use_sg=%d\n", - sfp->reserve.bufflen, sfp->reserve.use_sg)); - } + sfp, (int)sfp->fd_mem_src)); + sg_build_reserve(sfp, sg_big_buff); + SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", + sfp->reserve.bufflen, sfp->reserve.k_use_sg)); return sfp; } @@ -1560,17 +1982,13 @@ int dirty = 0; int res = 0; - if (sdp->merge_fd) { - if (--sdp->merge_fd) - return 0; /* if merge_fd then dec merge_fd counter */ - } srp = sfp->headrp; if (srp) { -/* Need to stop sg_command_done() playing with this list during this loop */ +/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ while (srp) { tsrp = srp->nextrp; - if (! srp->my_cmdp) - sg_finish_rem_req(srp, NULL, 0); + if (srp->done) + sg_finish_rem_req(srp); else ++dirty; srp = tsrp; @@ -1592,13 +2010,13 @@ } } if (sfp->reserve.bufflen > 0) { -SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, use_sg=%d\n", - (int)sfp->reserve.bufflen, (int)sfp->reserve.use_sg)); +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->my_mem_src); + 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); res = 1; } else { @@ -1621,6 +2039,18 @@ return 0; } +static int sg_dio_in_use(const Sg_fd * sfp) +{ + const Sg_request * srp = sfp->headrp; + + while (srp) { + if ((! srp->done) && srp->data.kiobp) + return 1; + srp = srp->nextrp; + } + return 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 */ @@ -1636,9 +2066,6 @@ /* Seen kmalloc(..,GFP_KERNEL) hang for 40 secs! */ resp = kmalloc(rqSz, page_mask); if (resp && retSzp) *retSzp = rqSz; -#ifdef SG_DEBUG - if (resp) ++sg_num_kmal; -#endif return resp; } if (SG_HEAP_POOL == mem_src) { @@ -1657,9 +2084,6 @@ if (resp) { if (retSzp) *retSzp = rqSz; sg_pool_secs_avail -= num_sect; -#ifdef SG_DEBUG - ++sg_num_pool; -#endif return resp; } } @@ -1684,16 +2108,13 @@ resSz = a_size; } if (retSzp) *retSzp = resSz; -#ifdef SG_DEBUG - if (resp) ++sg_num_page; -#endif } else printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz); return resp; } -static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, +static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp, int * mem_srcp) { char * resp = NULL; @@ -1705,7 +2126,7 @@ int low_dma = sfp->low_dma; int l_ms = -1; /* invalid value */ - switch (*mem_srcp) + switch (*mem_srcp) { case SG_HEAP_PAGE: l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE; @@ -1738,45 +2159,54 @@ } if (resp) *mem_srcp = l_ms; } - SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%p\n", + SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%p\n", size, *mem_srcp, resp)); return resp; } static void sg_low_free(char * buff, int size, int mem_src) { - if (! buff) - return; - if (SG_HEAP_POOL == mem_src) { - int num_sect = size / SG_SECTOR_SZ; - scsi_free(buff, size); - sg_pool_secs_avail += num_sect; - } - else if (SG_HEAP_KMAL == mem_src) - kfree(buff); /* size not used */ - else if (SG_HEAP_PAGE == mem_src) { - int order, a_size; - - for (order = 0, a_size = PAGE_SIZE; - a_size < size; order++, a_size <<= 1) - ; - free_pages((unsigned long)buff, order); - } - else - printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n", + if (! buff) return; + switch (mem_src) { + case SG_HEAP_POOL: + { + int num_sect = size / SG_SECTOR_SZ; + + scsi_free(buff, size); + sg_pool_secs_avail += num_sect; + } + break; + case SG_HEAP_KMAL: + kfree(buff); /* size not used */ + break; + case SG_HEAP_PAGE: + { + int order, a_size; + for (order = 0, a_size = PAGE_SIZE; + a_size < size; order++, a_size <<= 1) + ; + free_pages((unsigned long)buff, order); + } + break; + case SG_USER_MEM: + break; /* nothing to do */ + default: + printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n", mem_src, buff, size); + break; + } } static void sg_free(char * buff, int size, int mem_src) { - SCSI_LOG_TIMEOUT(6, + SCSI_LOG_TIMEOUT(6, printk("sg_free: buff=0x%p, size=%d\n", buff, size)); if ((! buff) || (size <= 0)) ; else sg_low_free(buff, size, mem_src); } - + static void sg_clr_scpnt(Scsi_Cmnd * SCpnt) { SCpnt->use_sg = 0; @@ -1787,3 +2217,391 @@ SCpnt->request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */ } +static int sg_ms_to_jif(unsigned int msecs) +{ + if ((UINT_MAX / 2U) < msecs) + return INT_MAX; /* special case, set largest possible */ + else + return ((int)msecs < (INT_MAX / 1000)) ? (((int)msecs * HZ) / 1000) + : (((int)msecs / 1000) * HZ); +} + +static unsigned sg_jif_to_ms(int jifs) +{ + if (jifs <= 0) + return 0U; + else { + unsigned int j = (unsigned int)jifs; + return (j < (UINT_MAX / 1000)) ? ((j * 1000) / HZ) : ((j / HZ) * 1000); + } +} + +static unsigned char allow_ops[] = {TEST_UNIT_READY, INQUIRY, +READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12}; + +static int sg_allow_access(unsigned char opcode, char dev_type) +{ + int k; + + if (TYPE_SCANNER == dev_type) /* TYPE_ROM maybe burner */ + return 1; + for (k = 0; k < sizeof(allow_ops); ++k) { + if (opcode == allow_ops[k]) + return 1; + } + return 0; +} + + +static int sg_last_dev() +{ + int k; + for (k = sg_template.dev_max - 1; k >= 0; --k) { + if (sg_dev_arr[k].device) + return k + 1; + } + return 0; /* origin 1 */ +} + +#ifdef CONFIG_PROC_FS + +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 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, + off_t offset, int size); +static int sg_proc_dressz_write(struct file * filp, const char * buffer, + unsigned long count, void * data); +static int sg_proc_debug_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, + off_t offset, int size); +static int sg_proc_dev_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +static int sg_proc_dev_info(char * buffer, int * len, off_t * begin, + off_t offset, int size); +static int sg_proc_devhdr_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +static int sg_proc_devhdr_info(char * buffer, int * len, off_t * begin, + off_t offset, int size); +static int sg_proc_devstrs_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +static int sg_proc_devstrs_info(char * buffer, int * len, off_t * begin, + off_t offset, int size); +static int sg_proc_host_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +static int sg_proc_host_info(char * buffer, int * len, off_t * begin, + off_t offset, int size); +static int sg_proc_hosthdr_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +static int sg_proc_hosthdr_info(char * buffer, int * len, off_t * begin, + off_t offset, int size); +static int sg_proc_hoststrs_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin, + off_t offset, int size); +static int sg_proc_version_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data); +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_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}; + +#define PRINT_PROC(fmt,args...) \ + do { \ + *len += sprintf(buffer + *len, fmt, ##args); \ + if (*begin + *len > offset + size) \ + return 0; \ + if (*begin + *len < offset) { \ + *begin += *len; \ + *len = 0; \ + } \ + } while(0) + +#define SG_PROC_READ_FN(infofp) \ + do { \ + int len = 0; \ + off_t begin = 0; \ + *eof = infofp(buffer, &len, &begin, offset, size); \ + if (offset >= (begin + len)) \ + return 0; \ + *start = buffer + ((begin > offset) ? \ + (begin - offset) : (offset - begin)); \ + return (size < (begin + len - offset)) ? \ + size : begin + len - offset; \ + } while(0) + + +static int sg_proc_init() +{ + int k, mask; + int leaves = sizeof(sg_proc_leaf_names) / sizeof(sg_proc_leaf_names[0]); + struct proc_dir_entry * pdep; + + if (! proc_scsi) + return 1; + sg_proc_sgp = create_proc_entry(sg_proc_sg_dirname, + S_IFDIR | S_IRUGO | S_IXUGO, proc_scsi); + if (! sg_proc_sgp) + return 1; + for (k = 0; k < leaves; ++k) { + mask = sg_proc_leaf_writes[k] ? S_IRUGO | S_IWUSR : S_IRUGO; + pdep = create_proc_entry(sg_proc_leaf_names[k], mask, sg_proc_sgp); + if (pdep) { + pdep->read_proc = sg_proc_leaf_reads[k]; + if (sg_proc_leaf_writes[k]) + pdep->write_proc = sg_proc_leaf_writes[k]; + } + } + return 0; +} + +static void sg_proc_cleanup() +{ + int k; + int leaves = sizeof(sg_proc_leaf_names) / sizeof(sg_proc_leaf_names[0]); + + if ((! proc_scsi) || (! sg_proc_sgp)) + return; + for (k = 0; k < leaves; ++k) + remove_proc_entry(sg_proc_leaf_names[k], sg_proc_sgp); + remove_proc_entry(sg_proc_sg_dirname, proc_scsi); +} + +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); } + +static int sg_proc_dressz_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + PRINT_PROC("%d\n", sg_big_buff); + return 1; +} + +static int sg_proc_dressz_write(struct file * filp, const char * buffer, + unsigned long count, void * data) +{ + int num; + unsigned long k = ULONG_MAX; + char buff[11]; + + if (! capable(CAP_SYS_ADMIN)) + return -EACCES; + num = (count < 10) ? count : 10; + copy_from_user(buff, buffer, num); + buff[count] = '\0'; + k = simple_strtoul(buff, 0, 10); + if (k <= 1048576) { + sg_big_buff = k; + return count; + } + return -ERANGE; +} + +static int sg_proc_debug_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_debug_info); } + +static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + const Sg_device * sdp = sg_dev_arr; + const sg_io_hdr_t * hp; + int j, max_dev; + + if (NULL == sg_dev_arr) { + PRINT_PROC("sg_dev_arr NULL, death is imminent\n"); + return 1; + } + max_dev = sg_last_dev(); + PRINT_PROC("dev_max=%d max_active_device=%d (origin 1)\n", + sg_template.dev_max, max_dev); + PRINT_PROC(" scsi_dma_free_sectors=%u sg_pool_secs_aval=%d " + "def_reserved_size=%d\n", + scsi_dma_free_sectors, sg_pool_secs_avail, sg_big_buff); + max_dev = sg_last_dev(); + for (j = 0; j < max_dev; ++j, ++sdp) { + if (sdp) { + Sg_fd * fp; + Sg_request * srp; + struct scsi_device * scsidp; + int dev, k, blen, usg, crep; + + if (! (scsidp = sdp->device)) { + PRINT_PROC("device %d detached ??\n", j); + continue; + } + dev = MINOR(sdp->i_rdev); + crep = 'a' + dev; + + PRINT_PROC(" >>> device=%d(sg%c) ", dev, crep > 126 ? '?' : crep); + 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); + fp = sdp->headfp; + for (k = 1; fp; fp = fp->nextfp, ++k) { + PRINT_PROC(" FD(%d): timeout=%d bufflen=%d " + "(res)sgat=%d low_dma=%d\n", + k, fp->timeout, fp->reserve.bufflen, + (int)fp->reserve.k_use_sg, (int)fp->low_dma); + PRINT_PROC(" cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n", + (int)fp->cmd_q, (int)fp->force_packid, + (int)fp->keep_orphan, (int)fp->closed); + srp = fp->headrp; + if (NULL == srp) + PRINT_PROC(" No requests active\n"); + while (srp) { + hp = &srp->header; +/* stop indenting so far ... */ + PRINT_PROC(srp->res_used ? " reserved_buff>> " : + ((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " ")); + blen = srp->my_cmdp ? srp->my_cmdp->bufflen : srp->data.bufflen; + usg = srp->my_cmdp ? srp->my_cmdp->use_sg : srp->data.k_use_sg; + PRINT_PROC(srp->done ? "rcv: id=%d" : (srp->my_cmdp ? "act: id=%d" : + "prior: id=%d"), srp->header.pack_id); + if (! srp->res_used) PRINT_PROC(" blen=%d", blen); + if (srp->done) + PRINT_PROC(" dur=%d", sg_jif_to_ms(hp->duration)); + else + PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ? + sg_jif_to_ms(fp->timeout) : hp->timeout), + sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0)); + PRINT_PROC(" sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode); + srp = srp->nextrp; +/* reset indenting */ + } + } + } + } + return 1; +} + +static int sg_proc_dev_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_dev_info); } + +static int sg_proc_dev_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + const Sg_device * sdp = sg_dev_arr; + int j, max_dev; + struct scsi_device * scsidp; + + max_dev = sg_last_dev(); + for (j = 0; j < max_dev; ++j, ++sdp) { + if (sdp) { + if (! (scsidp = sdp->device)) { + PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); + continue; + } + PRINT_PROC("%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->disconnect, + (int)scsidp->queue_depth, (int)scsidp->tagged_queue); + } + } + return 1; +} + +static int sg_proc_devhdr_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_devhdr_info); } + +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\tdiscon\tqdepth\ttq\n"); + return 1; +} + +static int sg_proc_devstrs_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_devstrs_info); } + +static int sg_proc_devstrs_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + const Sg_device * sdp = sg_dev_arr; + int j, max_dev; + struct scsi_device * scsidp; + + max_dev = sg_last_dev(); + for (j = 0; j < max_dev; ++j, ++sdp) { + if (sdp) { + if ((scsidp = sdp->device)) + PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n", + scsidp->vendor, scsidp->model, scsidp->rev); + else + PRINT_PROC("\n"); + } + } + return 1; +} + +static int sg_proc_host_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_host_info); } + +static int sg_proc_host_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + struct Scsi_Host * shp; + + for (shp = scsi_hostlist; shp; shp = shp->next) + PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n", + shp->unique_id, shp->host_busy, shp->cmd_per_lun, + shp->sg_tablesize, (int)shp->unchecked_isa_dma, + (int)shp->hostt->emulated); + return 1; +} + +static int sg_proc_hosthdr_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_hosthdr_info); } + +static int sg_proc_hosthdr_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + PRINT_PROC("uid\tbusy\tcpl\tscatg\tisa\temul\n"); + return 1; +} + +static int sg_proc_hoststrs_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_hoststrs_info); } + +static int sg_proc_hoststrs_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + struct Scsi_Host * shp; + + for (shp = scsi_hostlist; shp; shp = shp->next) + PRINT_PROC("%s\n", shp->hostt->info ? shp->hostt->info(shp) : + (shp->hostt->name ? shp->hostt->name : "")); + return 1; +} + +static int sg_proc_version_read(char * buffer, char ** start, off_t offset, + int size, int * eof, void * data) +{ SG_PROC_READ_FN(sg_proc_version_info); } + +static int sg_proc_version_info(char * buffer, int * len, off_t * begin, + off_t offset, int size) +{ + PRINT_PROC("%d\t%s\n", sg_version_num, sg_version_str); + return 1; +} +#endif /* CONFIG_PROC_FS */ diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.3.42/linux/drivers/scsi/sr.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/sr.c Wed Feb 9 18:40:24 2000 @@ -703,17 +703,17 @@ return 0; sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS; - scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); + scsi_CDs = (Scsi_CD *) kmalloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC); memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD)); - sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); + sr_sizes = (int *) kmalloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC); memset(sr_sizes, 0, sr_template.dev_max * sizeof(int)); - sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max * - sizeof(int), GFP_ATOMIC); + sr_blocksizes = (int *) kmalloc(sr_template.dev_max * + sizeof(int), GFP_ATOMIC); - sr_hardsizes = (int *) scsi_init_malloc(sr_template.dev_max * - sizeof(int), GFP_ATOMIC); + sr_hardsizes = (int *) kmalloc(sr_template.dev_max * + sizeof(int), GFP_ATOMIC); /* * These are good guesses for the time being. */ @@ -831,16 +831,14 @@ unregister_blkdev(MAJOR_NR, "sr"); sr_registered--; if (scsi_CDs != NULL) { - scsi_init_free((char *) scsi_CDs, - (sr_template.dev_noticed + SR_EXTRA_DEVS) - * sizeof(Scsi_CD)); + kfree((char *) scsi_CDs); - scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int)); + kfree((char *) sr_sizes); sr_sizes = NULL; - scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int)); + kfree((char *) sr_blocksizes); sr_blocksizes = NULL; - scsi_init_free((char *) sr_hardsizes, sr_template.dev_max * sizeof(int)); + kfree((char *) sr_hardsizes); sr_hardsizes = NULL; } blksize_size[MAJOR_NR] = NULL; diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.42/linux/drivers/scsi/st.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/scsi/st.c Wed Feb 9 11:42:35 2000 @@ -3217,17 +3217,12 @@ static struct file_operations st_fops = { - NULL, /* lseek - default */ - st_read, /* read - general block-dev read */ - st_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - st_ioctl, /* ioctl */ - NULL, /* mmap */ - scsi_tape_open, /* open */ - scsi_tape_flush, /* flush */ - scsi_tape_close, /* release */ - NULL /* fsync */ + read: st_read, + write: st_write, + ioctl: st_ioctl, + open: scsi_tape_open, + flush: scsi_tape_flush, + release: scsi_tape_close, }; static int st_attach(Scsi_Device * SDp) diff -u --recursive --new-file v2.3.42/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c --- v2.3.42/linux/drivers/scsi/u14-34f.c Tue Dec 14 01:27:24 1999 +++ linux/drivers/scsi/u14-34f.c Wed Feb 9 18:40:24 2000 @@ -826,7 +826,7 @@ } else { unsigned long flags; -//FIXME// sh[j]->wish_block = TRUE; + scsi_register_blocked_host(sh[j]); sh[j]->unchecked_isa_dma = TRUE; flags=claim_dma_lock(); @@ -1947,6 +1947,10 @@ if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n", driver_name); + + if( sh[j]->block != NULL ) { + scsi_deregister_blocked_host(sh[j]); + } for (i = 0; i < sh[j]->can_queue; i++) if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); diff -u --recursive --new-file v2.3.42/linux/drivers/sgi/char/ds1286.c linux/drivers/sgi/char/ds1286.c --- v2.3.42/linux/drivers/sgi/char/ds1286.c Fri Sep 10 23:57:35 1999 +++ linux/drivers/sgi/char/ds1286.c Wed Feb 9 11:42:35 2000 @@ -373,16 +373,12 @@ */ static struct file_operations ds1286_fops = { - ds1286_llseek, - ds1286_read, - NULL, /* No write */ - NULL, /* No readdir */ - ds1286_poll, - ds1286_ioctl, - NULL, /* No mmap */ - ds1286_open, - NULL, - ds1286_release + llseek: ds1286_llseek, + read: ds1286_read, + poll: ds1286_poll, + ioctl: ds1286_ioctl, + open: ds1286_open, + release: ds1286_release, }; static struct miscdevice ds1286_dev= diff -u --recursive --new-file v2.3.42/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c --- v2.3.42/linux/drivers/sgi/char/graphics.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sgi/char/graphics.c Wed Feb 9 11:42:35 2000 @@ -287,18 +287,10 @@ #endif struct file_operations sgi_graphics_fops = { - NULL, /* llseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - sgi_graphics_ioctl, /* ioctl */ - sgi_graphics_mmap, /* mmap */ - sgi_graphics_open, /* open */ - NULL, /* flush */ - sgi_graphics_close, /* release */ - NULL, /* fsync */ - NULL /* lock */ + ioctl: sgi_graphics_ioctl, + mmap: sgi_graphics_mmap, + open: sgi_graphics_open, + release: sgi_graphics_close, }; /* /dev/graphics */ diff -u --recursive --new-file v2.3.42/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c --- v2.3.42/linux/drivers/sgi/char/shmiq.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sgi/char/shmiq.c Wed Feb 9 11:42:35 2000 @@ -429,21 +429,14 @@ } -static struct -file_operations shmiq_fops = +static struct file_operations shmiq_fops = { - NULL, /* seek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - shmiq_qcntl_poll, /* poll */ - shmiq_qcntl_ioctl, /* ioctl */ - shmiq_qcntl_mmap, /* mmap */ - shmiq_qcntl_open, /* open */ - NULL, /* flush */ - shmiq_qcntl_close, /* close */ - NULL, /* fsync */ - shmiq_qcntl_fasync, /* fasync */ + poll: shmiq_qcntl_poll, + ioctl: shmiq_qcntl_ioctl, + mmap: shmiq_qcntl_mmap, + open: shmiq_qcntl_open, + release: shmiq_qcntl_close, + fasync: shmiq_qcntl_fasync, }; void diff -u --recursive --new-file v2.3.42/linux/drivers/sgi/char/streamable.c linux/drivers/sgi/char/streamable.c --- v2.3.42/linux/drivers/sgi/char/streamable.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sgi/char/streamable.c Wed Feb 9 11:42:35 2000 @@ -72,18 +72,9 @@ } struct file_operations sgi_gfx_fops = { - NULL, /* llseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - sgi_gfx_ioctl, /* ioctl */ - NULL, /* mmap */ - sgi_gfx_open, /* open */ - NULL, /* flush */ - sgi_gfx_close, /* release */ - NULL, /* fsync */ - NULL /* lock */ + ioctl: sgi_gfx_ioctl, + open: sgi_gfx_open, + release: sgi_gfx_close, }; static struct miscdevice dev_gfx = { @@ -191,18 +182,8 @@ } struct file_operations sgi_keyb_fops = { - NULL, /* llseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - sgi_keyb_ioctl, /* ioctl */ - NULL, /* mmap */ - sgi_keyb_open, /* open */ - NULL, /* flush */ - NULL, /* release */ - NULL, /* fsync */ - NULL /* lock */ + ioctl: sgi_keyb_ioctl, + open: sgi_keyb_open, }; static struct miscdevice dev_input_keyboard = { @@ -330,18 +311,9 @@ } struct file_operations sgi_mouse_fops = { - NULL, /* llseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - sgi_mouse_ioctl, /* ioctl */ - NULL, /* mmap */ - sgi_mouse_open, /* open */ - NULL, /* flush */ - sgi_mouse_close, /* release */ - NULL, /* fsync */ - NULL /* lock */ + ioctl: sgi_mouse_ioctl, + open: sgi_mouse_open, + release: sgi_mouse_close, }; /* /dev/input/mouse */ diff -u --recursive --new-file v2.3.42/linux/drivers/sgi/char/usema.c linux/drivers/sgi/char/usema.c --- v2.3.42/linux/drivers/sgi/char/usema.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sgi/char/usema.c Wed Feb 9 11:42:35 2000 @@ -170,18 +170,10 @@ } struct file_operations sgi_usemaclone_fops = { - NULL, /* llseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - sgi_usemaclone_poll, /* poll */ - sgi_usemaclone_ioctl, /* ioctl */ - NULL, /* mmap */ - sgi_usemaclone_open, /* open */ - NULL, /* flush */ - sgi_usemaclone_release, /* release */ - NULL, /* fsync */ - NULL /* lock */ + poll: sgi_usemaclone_poll, + ioctl: sgi_usemaclone_ioctl, + open: sgi_usemaclone_open, + release: sgi_usemaclone_release, }; static struct miscdevice dev_usemaclone = { diff -u --recursive --new-file v2.3.42/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.3.42/linux/drivers/sound/Makefile Tue Feb 1 01:35:44 2000 +++ linux/drivers/sound/Makefile Wed Feb 9 18:54:11 2000 @@ -53,7 +53,7 @@ obj-$(CONFIG_SOUND_CS4232) += uart401.o obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o -obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx.o sb.o uart401.o ac97.o +obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o sb.o uart401.o ac97.o obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o obj-$(CONFIG_SOUND_MPU401) += mpu401.o obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o @@ -81,7 +81,7 @@ obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o obj-$(CONFIG_SOUND_CMPCI) += cmpci.o obj-$(CONFIG_SOUND_ES1370) += es1370.o -obj-$(CONFIG_SOUND_ES1371) += es1371.o +obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o diff -u --recursive --new-file v2.3.42/linux/drivers/sound/ac97_codec.h linux/drivers/sound/ac97_codec.h --- v2.3.42/linux/drivers/sound/ac97_codec.h Tue Feb 1 01:35:44 2000 +++ linux/drivers/sound/ac97_codec.h Thu Feb 10 12:22:03 2000 @@ -154,4 +154,5 @@ }; extern int ac97_probe_codec(struct ac97_codec *); -#endif + +#endif /* _AC97_CODEC_H_ */ diff -u --recursive --new-file v2.3.42/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.3.42/linux/drivers/sound/cmpci.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sound/cmpci.c Wed Feb 9 11:42:35 2000 @@ -1180,19 +1180,10 @@ } static /*const*/ struct file_operations cm_mixer_fops = { - &cm_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &cm_ioctl_mixdev, - NULL, /* mmap */ - &cm_open_mixdev, - NULL, /* flush */ - &cm_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: cm_llseek, + ioctl: cm_ioctl_mixdev, + open: cm_open_mixdev, + release: cm_release_mixdev, }; /* --------------------------------------------------------------------- */ @@ -1801,19 +1792,14 @@ } static /*const*/ struct file_operations cm_audio_fops = { - &cm_llseek, - &cm_read, - &cm_write, - NULL, /* readdir */ - &cm_poll, - &cm_ioctl, - &cm_mmap, - &cm_open, - NULL, /* flush */ - &cm_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: cm_llseek, + read: cm_read, + write: cm_write, + poll: cm_poll, + ioctl: cm_ioctl, + mmap: cm_mmap, + open: cm_open, + release: cm_release, }; /* --------------------------------------------------------------------- */ @@ -2080,19 +2066,12 @@ } static /*const*/ struct file_operations cm_midi_fops = { - &cm_llseek, - &cm_midi_read, - &cm_midi_write, - NULL, /* readdir */ - &cm_midi_poll, - NULL, /* ioctl */ - NULL, /* mmap */ - &cm_midi_open, - NULL, /* flush */ - &cm_midi_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: cm_llseek, + read: cm_midi_read, + write: cm_midi_write, + poll: cm_midi_poll, + open: cm_midi_open, + release: cm_midi_release, }; /* --------------------------------------------------------------------- */ @@ -2252,19 +2231,10 @@ } static /*const*/ struct file_operations cm_dmfm_fops = { - &cm_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &cm_dmfm_ioctl, - NULL, /* mmap */ - &cm_dmfm_open, - NULL, /* flush */ - &cm_dmfm_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: cm_llseek, + ioctl: cm_dmfm_ioctl, + open: cm_dmfm_open, + release: cm_dmfm_release, }; /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.42/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.3.42/linux/drivers/sound/dev_table.c Tue May 11 23:40:50 1999 +++ linux/drivers/sound/dev_table.c Thu Feb 10 12:32:03 2000 @@ -13,6 +13,7 @@ */ #include +#include #define _DEV_TABLE_C_ @@ -313,9 +314,12 @@ return 0; } -void sound_setup(char *str, int *ints) +static int __init sound_setup(char *str) { int i, n = num_sound_cards; + int ints[32]; + + str = get_options(str, ARRAY_SIZE(ints), ints); /* * First disable all drivers @@ -325,7 +329,7 @@ snd_installed_cards[i].enabled = 0; if (ints[0] == 0 || ints[1] == 0) - return; + return 1; /* * Then enable them one by time */ @@ -343,7 +347,7 @@ /* * Add any future extensions here */ - return; + return 1; } ioaddr = (val & 0x000fff00) >> 8; irq = (val & 0x000000f0) >> 4; @@ -376,7 +380,11 @@ snd_installed_cards[ptr].config.card_subtype = 0; } } + + return 1; } + +__setup("sound=", sound_setup); struct address_info * sound_getconf(int card_type) diff -u --recursive --new-file v2.3.42/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.3.42/linux/drivers/sound/dev_table.h Fri Oct 22 13:21:50 1999 +++ linux/drivers/sound/dev_table.h Thu Feb 10 12:32:03 2000 @@ -717,7 +717,10 @@ void sound_unload_drivers(void); void sound_unload_driver(int type); int sndtable_identify_card(char *name); + +#if FIXED_FOR_2_4_0 void sound_setup (char *str, int *ints); +#endif extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); int sndtable_probe (int unit, struct address_info *hw_config); diff -u --recursive --new-file v2.3.42/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.3.42/linux/drivers/sound/dmasound.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sound/dmasound.c Thu Feb 10 12:31:07 2000 @@ -4605,16 +4605,10 @@ static struct file_operations mixer_fops = { - sound_lseek, - NULL, /* mixer_read */ - NULL, /* mixer_write */ - NULL, /* mixer_readdir */ - NULL, /* mixer_poll */ - mixer_ioctl, - NULL, /* mixer_mmap */ - mixer_open, - NULL, /* flush */ - mixer_release, + llseek: sound_lseek, + ioctl: mixer_ioctl, + open: mixer_open, + release: mixer_release, }; @@ -5231,20 +5225,14 @@ static struct file_operations sq_fops = { - sound_lseek, + llseek: sound_lseek, + write: sq_write, + ioctl: sq_ioctl, + open: sq_open, + release: sq_release, #ifdef CONFIG_PPC - sq_read, /* sq_read */ -#else - NULL, /* sq_read */ + read: sq_read, /* sq_read */ #endif - sq_write, - NULL, /* sq_readdir */ - NULL, /* sq_poll */ - sq_ioctl, - NULL, /* sq_mmap */ - sq_open, - NULL, /* flush */ - sq_release, }; @@ -5449,16 +5437,10 @@ static struct file_operations state_fops = { - sound_lseek, - state_read, - NULL, /* state_write */ - NULL, /* state_readdir */ - NULL, /* state_poll */ - NULL, /* state_ioctl */ - NULL, /* state_mmap */ - state_open, - NULL, /* flush */ - state_release, + llseek: sound_lseek, + read: state_read, + open: state_open, + release: state_release, }; @@ -5700,10 +5682,12 @@ } -#define MAXARGS 8 /* Should be sufficient for now */ - -void __init dmasound_setup(char *str, int *ints) +static int __init dmasound_setup(char *str) { + int ints[6]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + /* check the bootstrap parameter for "dmasound=" */ switch (ints[0]) { @@ -5727,8 +5711,13 @@ break; default: printk("dmasound_setup: illegal number of arguments\n"); + return 0; } + + return 1; } + +__setup("dmasound=", dmasound_setup); #ifdef MODULE diff -u --recursive --new-file v2.3.42/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.3.42/linux/drivers/sound/es1370.c Fri Jan 21 18:19:17 2000 +++ linux/drivers/sound/es1370.c Wed Feb 9 11:42:35 2000 @@ -116,6 +116,7 @@ * 28.10.1999 0.31 More waitqueue races fixed * 08.01.2000 0.32 Prevent some ioctl's from returning bad count values on underrun/overrun; * Tim Janik's BSE (Bedevilled Sound Engine) found this + * 07.02.2000 0.33 Use pci_alloc_consistent and pci_register_driver * * some important things missing in Ensoniq documentation: * @@ -307,8 +308,11 @@ /* magic */ unsigned int magic; - /* we keep sb cards in a linked list */ - struct es1370_state *next; + /* list of es1370 devices */ + struct list_head devs; + + /* the corresponding pci_dev structure */ + struct pci_dev *dev; /* soundcore stuff */ int dev_audio; @@ -340,6 +344,7 @@ struct dmabuf { void *rawbuf; + dma_addr_t dmaaddr; unsigned buforder; unsigned numfrag; unsigned fragshift; @@ -374,7 +379,7 @@ /* --------------------------------------------------------------------- */ -static struct es1370_state *devs = NULL; +static LIST_HEAD(devs); /* * The following buffer is used to point the phantom write channel to, @@ -532,7 +537,7 @@ #define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 -extern inline void dealloc_dmabuf(struct dmabuf *db) +extern inline void dealloc_dmabuf(struct es1370_state *s, struct dmabuf *db) { unsigned long map, mapend; @@ -541,7 +546,7 @@ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (map = MAP_NR(db->rawbuf); map <= mapend; map++) clear_bit(PG_reserved, &mem_map[map].flags); - free_pages((unsigned long)db->rawbuf, db->buforder); + pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); } db->rawbuf = NULL; db->mapped = db->ready = 0; @@ -558,7 +563,7 @@ if (!db->rawbuf) { db->ready = db->mapped = 0; for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order))) + if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) break; if (!db->rawbuf) return -ENOMEM; @@ -593,7 +598,7 @@ db->dmasize = db->numfrag << db->fragshift; memset(db->rawbuf, (fmt & ES1370_FMT_S16) ? 0 : 0x80, db->dmasize); outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE); - outl(virt_to_bus(db->rawbuf), s->io+(reg & 0xff)); + outl(db->dmaaddr, s->io+(reg & 0xff)); outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); db->ready = 1; return 0; @@ -1013,12 +1018,16 @@ static int es1370_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct es1370_state *s = devs; + struct list_head *list; + struct es1370_state *s; - while (s && s->dev_mixer != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct es1370_state, devs); + if (s->dev_mixer == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; MOD_INC_USE_COUNT; @@ -1040,19 +1049,10 @@ } static /*const*/ struct file_operations es1370_mixer_fops = { - &es1370_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &es1370_ioctl_mixdev, - NULL, /* mmap */ - &es1370_open_mixdev, - NULL, /* flush */ - &es1370_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: es1370_llseek, + ioctl: es1370_ioctl_mixdev, + open: es1370_open_mixdev, + release: es1370_release_mixdev, }; /* --------------------------------------------------------------------- */ @@ -1655,13 +1655,17 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct es1370_state *s = devs; unsigned long flags; + struct list_head *list; + struct es1370_state *s; - while (s && ((s->dev_audio ^ minor) & ~0xf)) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct es1370_state, devs); + if (!((s->dev_audio ^ minor) & ~0xf)) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -1720,11 +1724,11 @@ if (file->f_mode & FMODE_WRITE) { stop_dac2(s); synchronize_irq(); - dealloc_dmabuf(&s->dma_dac2); + dealloc_dmabuf(s, &s->dma_dac2); } if (file->f_mode & FMODE_READ) { stop_adc(s); - dealloc_dmabuf(&s->dma_adc); + dealloc_dmabuf(s, &s->dma_adc); } s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); wake_up(&s->open_wait); @@ -1734,19 +1738,14 @@ } static /*const*/ struct file_operations es1370_audio_fops = { - &es1370_llseek, - &es1370_read, - &es1370_write, - NULL, /* readdir */ - &es1370_poll, - &es1370_ioctl, - &es1370_mmap, - &es1370_open, - NULL, /* flush */ - &es1370_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: es1370_llseek, + read: es1370_read, + write: es1370_write, + poll: es1370_poll, + ioctl: es1370_ioctl, + mmap: es1370_mmap, + open: es1370_open, + release: es1370_release, }; /* --------------------------------------------------------------------- */ @@ -2065,13 +2064,17 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct es1370_state *s = devs; unsigned long flags; + struct list_head *list; + struct es1370_state *s; - while (s && ((s->dev_dac ^ minor) & ~0xf)) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct es1370_state, devs); + if (!((s->dev_dac ^ minor) & ~0xf)) + break; + } VALIDATE_STATE(s); /* we allow opening with O_RDWR, most programs do it although they will only write */ #if 0 @@ -2123,7 +2126,7 @@ drain_dac1(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); stop_dac1(s); - dealloc_dmabuf(&s->dma_dac1); + dealloc_dmabuf(s, &s->dma_dac1); s->open_mode &= ~FMODE_DAC; wake_up(&s->open_wait); up(&s->open_sem); @@ -2132,19 +2135,13 @@ } static /*const*/ struct file_operations es1370_dac_fops = { - &es1370_llseek, - NULL, /* read */ - &es1370_write_dac, - NULL, /* readdir */ - &es1370_poll_dac, - &es1370_ioctl_dac, - &es1370_mmap_dac, - &es1370_open_dac, - NULL, /* flush */ - &es1370_release_dac, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: es1370_llseek, + write: es1370_write_dac, + poll: es1370_poll_dac, + ioctl: es1370_ioctl_dac, + mmap: es1370_mmap_dac, + open: es1370_open_dac, + release: es1370_release_dac, }; /* --------------------------------------------------------------------- */ @@ -2307,13 +2304,17 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct es1370_state *s = devs; unsigned long flags; + struct list_head *list; + struct es1370_state *s; - while (s && s->dev_midi != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct es1370_state, devs); + if (s->dev_midi == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -2404,30 +2405,25 @@ } static /*const*/ struct file_operations es1370_midi_fops = { - &es1370_llseek, - &es1370_midi_read, - &es1370_midi_write, - NULL, /* readdir */ - &es1370_midi_poll, - NULL, /* ioctl */ - NULL, /* mmap */ - &es1370_midi_open, - NULL, /* flush */ - &es1370_midi_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: es1370_llseek, + read: es1370_midi_read, + write: es1370_midi_write, + poll: es1370_midi_poll, + open: es1370_midi_open, + release: es1370_midi_release, }; /* --------------------------------------------------------------------- */ -/* maximum number of devices */ +/* maximum number of devices; only used for command line params */ #define NR_DEVICE 5 static int joystick[NR_DEVICE] = { 0, }; static int lineout[NR_DEVICE] = { 0, }; static int micbias[NR_DEVICE] = { 0, }; +static unsigned int devindex = 0; + MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i"); MODULE_PARM_DESC(joystick, "if 1 enables joystick interface (still need separate driver)"); MODULE_PARM(lineout, "1-" __MODULE_STRING(NR_DEVICE) "i"); @@ -2460,142 +2456,168 @@ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) - -static int __init init_es1370(void) +static int es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct es1370_state *s; - struct pci_dev *pcidev = NULL; mm_segment_t fs; - int i, val, index = 0; + int i, val; + + if (!RSRCISIOREGION(pcidev, 0)) + return -1; + if (pcidev->irq == 0) + return -1; + if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) { + printk(KERN_WARNING "es1370: out of memory\n"); + return -1; + } + memset(s, 0, sizeof(struct es1370_state)); + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac1.wait); + init_waitqueue_head(&s->dma_dac2.wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->midi.iwait); + init_waitqueue_head(&s->midi.owait); + init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); + s->magic = ES1370_MAGIC; + s->dev = pcidev; + s->io = RSRCADDRESS(pcidev, 0); + s->irq = pcidev->irq; + if (!request_region(s->io, ES1370_EXTENT, "es1370")) { + printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); + goto err_region; + } + if (request_irq(s->irq, es1370_interrupt, SA_SHIRQ, "es1370", s)) { + printk(KERN_ERR "es1370: irq %u in use\n", s->irq); + goto err_irq; + } + pci_enable_device(pcidev); + /* initialize codec registers */ + /* note: setting CTRL_SERR_DIS is reported to break + * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */ + s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); + if (joystick[devindex]) { + if (check_region(0x200, JOY_EXTENT)) + printk(KERN_ERR "es1370: io port 0x200 in use\n"); + else + s->ctrl |= CTRL_JYSTK_EN; + } + if (lineout[devindex]) + s->ctrl |= CTRL_XCTL0; + if (micbias[devindex]) + s->ctrl |= CTRL_XCTL1; + s->sctrl = 0; + printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n" + KERN_INFO "es1370: features: joystick %s, line %s, mic impedance %s\n", + s->io, s->irq, (s->ctrl & CTRL_JYSTK_EN) ? "on" : "off", + (s->ctrl & CTRL_XCTL0) ? "out" : "in", + (s->ctrl & CTRL_XCTL1) ? "1" : "0"); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) + goto err_dev1; + if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) + goto err_dev2; + if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) + goto err_dev3; + if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) + goto err_dev4; + /* initialize the chips */ + outl(s->ctrl, s->io+ES1370_REG_CONTROL); + outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); + /* point phantom write channel to "bugbuf" */ + outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE); + outl(virt_to_bus(bugbuf), s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff)); + outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff)); + pci_set_master(pcidev); /* enable bus mastering */ + wrcodec(s, 0x16, 3); /* no RST, PD */ + wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!! */ + wrcodec(s, 0x18, 0); /* recording source is mixer */ + wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */ + s->mix.imix = 1; + fs = get_fs(); + set_fs(KERNEL_DS); + val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD; + mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); + for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { + val = initvol[i].vol; + mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); + } + set_fs(fs); + /* store it in the driver field */ + pcidev->driver_data = s; + pcidev->dma_mask = 0xffffffff; + /* put it into driver list */ + list_add_tail(&s->devs, &devs); + /* increment devindex */ + if (devindex < NR_DEVICE-1) + devindex++; + return 0; + + err_dev4: + unregister_sound_dsp(s->dev_dac); + err_dev3: + unregister_sound_mixer(s->dev_mixer); + err_dev2: + unregister_sound_dsp(s->dev_audio); + err_dev1: + printk(KERN_ERR "es1370: cannot register misc device\n"); + free_irq(s->irq, s); + err_irq: + release_region(s->io, ES1370_EXTENT); + err_region: + kfree_s(s, sizeof(struct es1370_state)); + return -1; +} + +static void es1370_remove(struct pci_dev *dev) +{ + struct es1370_state *s = (struct es1370_state *)dev->driver_data; + + if (!s) + return; + list_del(&s->devs); + outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ + outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ + synchronize_irq(); + free_irq(s->irq, s); + release_region(s->io, ES1370_EXTENT); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->dev_mixer); + unregister_sound_dsp(s->dev_dac); + unregister_sound_midi(s->dev_midi); + kfree_s(s, sizeof(struct es1370_state)); + dev->driver_data = NULL; +} + +static const struct pci_device_id id_table[] = { + { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +MODULE_DEVICE_TABLE(pci, id_table); + +static struct pci_driver es1370_driver = { + name: "es1370", + id_table: id_table, + probe: es1370_probe, + remove: es1370_remove +}; +static int __init init_es1370(void) +{ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.32 time " __TIME__ " " __DATE__ "\n"); - while (index < NR_DEVICE && - (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { - if (!RSRCISIOREGION(pcidev, 0)) - continue; - if (pcidev->irq == 0) - continue; - if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) { - printk(KERN_WARNING "es1370: out of memory\n"); - continue; - } - memset(s, 0, sizeof(struct es1370_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac1.wait); - init_waitqueue_head(&s->dma_dac2.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - init_MUTEX(&s->open_sem); - spin_lock_init(&s->lock); - s->magic = ES1370_MAGIC; - s->io = RSRCADDRESS(pcidev, 0); - s->irq = pcidev->irq; - if (check_region(s->io, ES1370_EXTENT)) { - printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1); - goto err_region; - } - request_region(s->io, ES1370_EXTENT, "es1370"); - if (request_irq(s->irq, es1370_interrupt, SA_SHIRQ, "es1370", s)) { - printk(KERN_ERR "es1370: irq %u in use\n", s->irq); - goto err_irq; - } - /* initialize codec registers */ - /* note: setting CTRL_SERR_DIS is reported to break - * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */ - s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); - if (joystick[index]) { - if (check_region(0x200, JOY_EXTENT)) - printk(KERN_ERR "es1370: io port 0x200 in use\n"); - else - s->ctrl |= CTRL_JYSTK_EN; - } - if (lineout[index]) - s->ctrl |= CTRL_XCTL0; - if (micbias[index]) - s->ctrl |= CTRL_XCTL1; - s->sctrl = 0; - printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n" - KERN_INFO "es1370: features: joystick %s, line %s, mic impedance %s\n", - s->io, s->irq, (s->ctrl & CTRL_JYSTK_EN) ? "on" : "off", - (s->ctrl & CTRL_XCTL0) ? "out" : "in", - (s->ctrl & CTRL_XCTL1) ? "1" : "0"); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) - goto err_dev2; - if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) - goto err_dev3; - if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) - goto err_dev4; - /* initialize the chips */ - outl(s->ctrl, s->io+ES1370_REG_CONTROL); - outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); - /* point phantom write channel to "bugbuf" */ - outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE); - outl(virt_to_bus(bugbuf), s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff)); - outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff)); - pci_set_master(pcidev); /* enable bus mastering */ - wrcodec(s, 0x16, 3); /* no RST, PD */ - wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!! */ - wrcodec(s, 0x18, 0); /* recording source is mixer */ - wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */ - s->mix.imix = 1; - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); - } - set_fs(fs); - /* queue it for later freeing */ - s->next = devs; - devs = s; - index++; - continue; - - err_dev4: - unregister_sound_dsp(s->dev_dac); - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR "es1370: cannot register misc device\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->io, ES1370_EXTENT); - err_region: - kfree_s(s, sizeof(struct es1370_state)); - } - if (!devs) + printk(KERN_INFO "es1370: version v0.33 time " __TIME__ " " __DATE__ "\n"); + if (!pci_register_driver(&es1370_driver)) return -ENODEV; - return 0; + return 0; + } static void __exit cleanup_es1370(void) { - struct es1370_state *s; - - while ((s = devs)) { - devs = devs->next; - outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ - outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ - synchronize_irq(); - free_irq(s->irq, s); - release_region(s->io, ES1370_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_dsp(s->dev_dac); - unregister_sound_midi(s->dev_midi); - kfree_s(s, sizeof(struct es1370_state)); - } printk(KERN_INFO "es1370: unloading\n"); + pci_unregister_driver(&es1370_driver); } module_init(init_es1370); diff -u --recursive --new-file v2.3.42/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.3.42/linux/drivers/sound/es1371.c Fri Jan 21 18:19:17 2000 +++ linux/drivers/sound/es1371.c Wed Feb 9 11:42:35 2000 @@ -98,6 +98,8 @@ * Eric Lemar, elemar@cs.washington.edu * 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun; * Tim Janik's BSE (Bedevilled Sound Engine) found this + * 07.02.2000 0.24 Use pci_alloc_consistent and pci_register_driver + * 07.02.2000 0.25 Use ac97_codec */ /*****************************************************************************/ @@ -121,7 +123,7 @@ #include #include #include -#include "ac97.h" +#include "ac97_codec.h" /* --------------------------------------------------------------------- */ @@ -376,49 +378,18 @@ /* --------------------------------------------------------------------- */ -static const char *stereo_enhancement[] __initdata = -{ - "no 3D stereo enhancement", - "Analog Devices Phat Stereo", - "Creative Stereo Enhancement", - "National Semiconductor 3D Stereo Enhancement", - "YAMAHA Ymersion", - "BBE 3D Stereo Enhancement", - "Crystal Semiconductor 3D Stereo Enhancement", - "Qsound QXpander", - "Spatializer 3D Stereo Enhancement", - "SRS 3D Stereo Enhancement", - "Platform Technologies 3D Stereo Enhancement", - "AKM 3D Audio", - "Aureal Stereo Enhancement", - "AZTECH 3D Enhancement", - "Binaura 3D Audio Enhancement", - "ESS Technology Stereo Enhancement", - "Harman International VMAx", - "NVidea 3D Stereo Enhancement", - "Philips Incredible Sound", - "Texas Instruments 3D Stereo Enhancement", - "VLSI Technology 3D Stereo Enhancement", - NULL, - NULL, - NULL, - NULL, - NULL, - "SigmaTel SS3D" -}; - -/* --------------------------------------------------------------------- */ - struct es1371_state { /* magic */ unsigned int magic; - /* we keep sb cards in a linked list */ - struct es1371_state *next; + /* list of es1371 devices */ + struct list_head devs; + + /* the corresponding pci_dev structure */ + struct pci_dev *dev; /* soundcore stuff */ int dev_audio; - int dev_mixer; int dev_dac; int dev_midi; @@ -435,14 +406,8 @@ /* debug /proc entry */ struct proc_dir_entry *ps; #endif /* ES1371_DEBUG */ - /* mixer registers; there is no HW readback */ - struct { - unsigned short codec_id; - unsigned int modcnt; -#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS - unsigned short vol[13]; -#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - } mix; + + struct ac97_codec codec; /* wave stuff */ unsigned ctrl; @@ -456,6 +421,7 @@ struct dmabuf { void *rawbuf; + dma_addr_t dmaaddr; unsigned buforder; unsigned numfrag; unsigned fragshift; @@ -490,7 +456,7 @@ /* --------------------------------------------------------------------- */ -static struct es1371_state *devs = NULL; +static LIST_HEAD(devs); /* --------------------------------------------------------------------- */ @@ -707,8 +673,9 @@ /* --------------------------------------------------------------------- */ -static void wrcodec(struct es1371_state *s, unsigned addr, unsigned data) +static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) { + struct es1371_state *s = (struct es1371_state *)codec->private_data; unsigned long flags; unsigned t, x; @@ -721,7 +688,7 @@ x = wait_src_ready(s); /* enable SRC state data in SRC mux */ - outl(( x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000, + outl((x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000, s->io+ES1371_REG_SRCONV); /* wait for not busy (state 0) first to avoid @@ -748,8 +715,9 @@ spin_unlock_irqrestore(&s->lock, flags); } -static unsigned rdcodec(struct es1371_state *s, unsigned addr) +static u16 rdcodec(struct ac97_codec *codec, u8 addr) { + struct es1371_state *s = (struct es1371_state *)codec->private_data; unsigned long flags; unsigned t, x; @@ -907,7 +875,7 @@ #define DMABUF_MINORDER 1 -extern inline void dealloc_dmabuf(struct dmabuf *db) +extern inline void dealloc_dmabuf(struct es1371_state *s, struct dmabuf *db) { unsigned long map, mapend; @@ -915,8 +883,8 @@ /* undo marking the pages as reserved */ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (map = MAP_NR(db->rawbuf); map <= mapend; map++) - clear_bit(PG_reserved, &mem_map[map].flags); - free_pages((unsigned long)db->rawbuf, db->buforder); + clear_bit(PG_reserved, &mem_map[map].flags); + pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); } db->rawbuf = NULL; db->mapped = db->ready = 0; @@ -933,7 +901,7 @@ if (!db->rawbuf) { db->ready = db->mapped = 0; for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order))) + if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) break; if (!db->rawbuf) return -ENOMEM; @@ -968,7 +936,7 @@ db->dmasize = db->numfrag << db->fragshift; memset(db->rawbuf, (fmt & ES1371_FMT_S16) ? 0 : 0x80, db->dmasize); outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE); - outl(virt_to_bus(db->rawbuf), s->io+(reg & 0xff)); + outl(db->dmaaddr, s->io+(reg & 0xff)); outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); db->ready = 1; return 0; @@ -1157,6 +1125,13 @@ /* --------------------------------------------------------------------- */ +static loff_t es1371_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* --------------------------------------------------------------------- */ + /* * AC97 Mixer Register to Connections mapping of the Concert 97 board * @@ -1172,435 +1147,19 @@ * AC97_PCMOUT_VOL Wave Output (stereo) */ -#define AC97_PESSIMISTIC - -/* - * this define causes the driver to assume that all optional - * AC97 bits are missing. This is what Ensoniq does too in their - * Windows driver. Maybe we should one day autoprobe for these - * bits. But anyway I have to see an AC97 codec that implements - * one of those optional (volume) bits. - */ - -static const unsigned int recsrc[8] = -{ - SOUND_MASK_MIC, - SOUND_MASK_CD, - SOUND_MASK_VIDEO, - SOUND_MASK_LINE1, - SOUND_MASK_LINE, - SOUND_MASK_VOLUME, - SOUND_MASK_PHONEOUT, - SOUND_MASK_PHONEIN -}; - -static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = -{ - /* 5 bit stereo */ - [SOUND_MIXER_LINE] = AC97_LINEIN_VOL, - [SOUND_MIXER_CD] = AC97_CD_VOL, - [SOUND_MIXER_VIDEO] = AC97_VIDEO_VOL, - [SOUND_MIXER_LINE1] = AC97_AUX_VOL, - [SOUND_MIXER_PCM] = AC97_PCMOUT_VOL, - /* 6 bit stereo */ - [SOUND_MIXER_VOLUME] = AC97_MASTER_VOL_STEREO, - [SOUND_MIXER_PHONEOUT] = AC97_HEADPHONE_VOL, - /* 6 bit mono */ - [SOUND_MIXER_OGAIN] = AC97_MASTER_VOL_MONO, - [SOUND_MIXER_PHONEIN] = AC97_PHONE_VOL, - /* 4 bit mono but shifted by 1 */ - [SOUND_MIXER_SPEAKER] = AC97_MASTER_TONE, - /* 6 bit mono + preamp */ - [SOUND_MIXER_MIC] = AC97_MIC_VOL, - /* 4 bit stereo */ - [SOUND_MIXER_RECLEV] = AC97_RECORD_GAIN, - /* 4 bit mono */ - [SOUND_MIXER_IGAIN] = AC97_RECORD_GAIN_MIC -}; - -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - -#define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) - -static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg) -{ - int j; - - switch (ch) { - case SOUND_MIXER_MIC: - j = rdcodec(s, AC97_MIC_VOL); - if (j & AC97_MUTE) - return put_user(0, (int *)arg); -#ifdef AC97_PESSIMISTIC - return put_user(0x4949 - 0x202 * (j & 0x1f) + ((j & 0x40) ? 0x1b1b : 0), (int *)arg); -#else /* AC97_PESSIMISTIC */ - return put_user(0x5757 - 0x101 * ((j & 0x3f) * 5 / 4) + ((j & 0x40) ? 0x0d0d : 0), (int *)arg); -#endif /* AC97_PESSIMISTIC */ - - case SOUND_MIXER_OGAIN: - case SOUND_MIXER_PHONEIN: - j = rdcodec(s, volreg[ch]); - if (j & AC97_MUTE) - return put_user(0, (int *)arg); -#ifdef AC97_PESSIMISTIC - return put_user(0x6464 - 0x303 * (j & 0x1f), (int *)arg); -#else /* AC97_PESSIMISTIC */ - return put_user((0x6464 - 0x303 * (j & 0x3f) / 2) & 0x7f7f, (int *)arg); -#endif /* AC97_PESSIMISTIC */ - - case SOUND_MIXER_PHONEOUT: - if (!(s->mix.codec_id & CODEC_ID_HEADPHONEOUT)) - return -EINVAL; - /* fall through */ - case SOUND_MIXER_VOLUME: - j = rdcodec(s, volreg[ch]); - if (j & AC97_MUTE) - return put_user(0, (int *)arg); -#ifdef AC97_PESSIMISTIC - return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg); -#else /* AC97_PESSIMISTIC */ - return put_user((0x6464 - (swab(j) & 0x3f3f) * 3 / 2) & 0x7f7f, (int *)arg); -#endif /* AC97_PESSIMISTIC */ - - case SOUND_MIXER_SPEAKER: - j = rdcodec(s, AC97_PCBEEP_VOL); - if (j & AC97_MUTE) - return put_user(0, (int *)arg); - return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg); - - case SOUND_MIXER_LINE: - case SOUND_MIXER_CD: - case SOUND_MIXER_VIDEO: - case SOUND_MIXER_LINE1: - case SOUND_MIXER_PCM: - j = rdcodec(s, volreg[ch]); - if (j & AC97_MUTE) - return put_user(0, (int *)arg); - return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg); - - case SOUND_MIXER_BASS: - case SOUND_MIXER_TREBLE: - if (!(s->mix.codec_id & CODEC_ID_BASSTREBLE)) - return -EINVAL; - j = rdcodec(s, AC97_MASTER_TONE); - if (ch == SOUND_MIXER_BASS) - j >>= 8; - return put_user((((j & 15) * 100) / 15) * 0x101, (int *)arg); - - /* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */ - case SOUND_MIXER_RECLEV: - j = rdcodec(s, AC97_RECORD_GAIN); - if (j & AC97_MUTE) - return put_user(0, (int *)arg); - return put_user((swab(j) & 0xf0f) * 6 + 0xa0a, (int *)arg); - - case SOUND_MIXER_IGAIN: - if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC)) - return -EINVAL; - j = rdcodec(s, AC97_RECORD_GAIN_MIC); - if (j & AC97_MUTE) - return put_user(0, (int *)arg); - return put_user((j & 0xf) * 0x606 + 0xa0a, (int *)arg); - - default: - return -EINVAL; - } -} - -#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - -static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = -{ - /* 5 bit stereo */ - [SOUND_MIXER_LINE] = 1, - [SOUND_MIXER_CD] = 2, - [SOUND_MIXER_VIDEO] = 3, - [SOUND_MIXER_LINE1] = 4, - [SOUND_MIXER_PCM] = 5, - /* 6 bit stereo */ - [SOUND_MIXER_VOLUME] = 6, - [SOUND_MIXER_PHONEOUT] = 7, - /* 6 bit mono */ - [SOUND_MIXER_OGAIN] = 8, - [SOUND_MIXER_PHONEIN] = 9, - /* 4 bit mono but shifted by 1 */ - [SOUND_MIXER_SPEAKER] = 10, - /* 6 bit mono + preamp */ - [SOUND_MIXER_MIC] = 11, - /* 4 bit stereo */ - [SOUND_MIXER_RECLEV] = 12, - /* 4 bit mono */ - [SOUND_MIXER_IGAIN] = 13 -}; - -#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - -static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val) -{ - int i; - unsigned l1, r1; - - l1 = val & 0xff; - r1 = (val >> 8) & 0xff; - if (l1 > 100) - l1 = 100; - if (r1 > 100) - r1 = 100; - switch (ch) { - case SOUND_MIXER_LINE: - case SOUND_MIXER_CD: - case SOUND_MIXER_VIDEO: - case SOUND_MIXER_LINE1: - case SOUND_MIXER_PCM: - if (l1 < 7 && r1 < 7) { - wrcodec(s, volreg[ch], AC97_MUTE); - return 0; - } - if (l1 < 7) - l1 = 7; - if (r1 < 7) - r1 = 7; - wrcodec(s, volreg[ch], (((100 - l1) / 3) << 8) | ((100 - r1) / 3)); - return 0; - - case SOUND_MIXER_PHONEOUT: - if (!(s->mix.codec_id & CODEC_ID_HEADPHONEOUT)) - return -EINVAL; - /* fall through */ - case SOUND_MIXER_VOLUME: -#ifdef AC97_PESSIMISTIC - if (l1 < 7 && r1 < 7) { - wrcodec(s, volreg[ch], AC97_MUTE); - return 0; - } - if (l1 < 7) - l1 = 7; - if (r1 < 7) - r1 = 7; - wrcodec(s, volreg[ch], (((100 - l1) / 3) << 8) | ((100 - r1) / 3)); - return 0; -#else /* AC97_PESSIMISTIC */ - if (l1 < 4 && r1 < 4) { - wrcodec(s, volreg[ch], AC97_MUTE); - return 0; - } - if (l1 < 4) - l1 = 4; - if (r1 < 4) - r1 = 4; - wrcodec(s, volreg[ch], ((2 * (100 - l1) / 3) << 8) | (2 * (100 - r1) / 3)); - return 0; -#endif /* AC97_PESSIMISTIC */ - - case SOUND_MIXER_OGAIN: - case SOUND_MIXER_PHONEIN: -#ifdef AC97_PESSIMISTIC - wrcodec(s, volreg[ch], (l1 < 7) ? AC97_MUTE : (100 - l1) / 3); - return 0; -#else /* AC97_PESSIMISTIC */ - wrcodec(s, volreg[ch], (l1 < 4) ? AC97_MUTE : (2 * (100 - l1) / 3)); - return 0; -#endif /* AC97_PESSIMISTIC */ - - case SOUND_MIXER_SPEAKER: - wrcodec(s, AC97_PCBEEP_VOL, (l1 < 10) ? AC97_MUTE : ((100 - l1) / 6) << 1); - return 0; - - case SOUND_MIXER_MIC: -#ifdef AC97_PESSIMISTIC - if (l1 < 11) { - wrcodec(s, AC97_MIC_VOL, AC97_MUTE); - return 0; - } - i = 0; - if (l1 >= 27) { - l1 -= 27; - i = 0x40; - } - if (l1 < 11) - l1 = 11; - wrcodec(s, AC97_MIC_VOL, ((73 - l1) / 2) | i); - return 0; -#else /* AC97_PESSIMISTIC */ - if (l1 < 9) { - wrcodec(s, AC97_MIC_VOL, AC97_MUTE); - return 0; - } - i = 0; - if (l1 >= 13) { - l1 -= 13; - i = 0x40; - } - if (l1 < 9) - l1 = 9; - wrcodec(s, AC97_MIC_VOL, (((87 - l1) * 4) / 5) | i); - return 0; -#endif /* AC97_PESSIMISTIC */ - - case SOUND_MIXER_BASS: - val = ((l1 * 15) / 100) & 0xf; - wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0x00ff) | (val << 8)); - return 0; - - case SOUND_MIXER_TREBLE: - val = ((l1 * 15) / 100) & 0xf; - wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0xff00) | val); - return 0; - - /* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */ - case SOUND_MIXER_RECLEV: - if (l1 < 10 || r1 < 10) { - wrcodec(s, AC97_RECORD_GAIN, AC97_MUTE); - return 0; - } - if (l1 < 10) - l1 = 10; - if (r1 < 10) - r1 = 10; - wrcodec(s, AC97_RECORD_GAIN, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6)); - return 0; - - case SOUND_MIXER_IGAIN: - if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC)) - return -EINVAL; - wrcodec(s, AC97_RECORD_GAIN_MIC, (l1 < 10) ? AC97_MUTE : ((l1 - 10) / 6) & 0xf); - return 0; - - default: - return -EINVAL; - } -} - -static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long arg) -{ - int i, val; - - VALIDATE_STATE(s); - if (cmd == SOUND_MIXER_PRIVATE1) { - if (!(s->mix.codec_id & (CODEC_ID_SEMASK << CODEC_ID_SESHIFT))) - return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); - if (val & 1) - wrcodec(s, AC97_3D_CONTROL, ((val << 3) & 0xf00) | ((val >> 1) & 0xf)); - val = rdcodec(s, AC97_3D_CONTROL); - return put_user(((val & 0xf) << 1) | ((val & 0xf00) >> 3), (int *)arg); - } - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - strncpy(info.id, "ES1371", sizeof(info.id)); - strncpy(info.name, "Ensoniq ES1371", sizeof(info.name)); - info.modify_counter = s->mix.modcnt; - if (copy_to_user((void *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - strncpy(info.id, "ES1371", sizeof(info.id)); - strncpy(info.name, "Ensoniq ES1371", sizeof(info.name)); - if (copy_to_user((void *)arg, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int *)arg); - if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) - return -EINVAL; - if (_IOC_DIR(cmd) == _IOC_READ) { - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - return put_user(recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7], (int *)arg); - - case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ - return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO | - SOUND_MASK_LINE1 | SOUND_MASK_PCM | SOUND_MASK_VOLUME | - SOUND_MASK_OGAIN | SOUND_MASK_PHONEIN | SOUND_MASK_SPEAKER | - SOUND_MASK_MIC | SOUND_MASK_RECLEV | - ((s->mix.codec_id & CODEC_ID_BASSTREBLE) ? (SOUND_MASK_BASS | SOUND_MASK_TREBLE) : 0) | - ((s->mix.codec_id & CODEC_ID_HEADPHONEOUT) ? SOUND_MASK_PHONEOUT : 0) | - ((s->mix.codec_id & CODEC_ID_DEDICATEDMIC) ? SOUND_MASK_IGAIN : 0), (int *)arg); - - case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ - return put_user(SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VIDEO | SOUND_MASK_LINE1 | - SOUND_MASK_LINE | SOUND_MASK_VOLUME | SOUND_MASK_PHONEOUT | - SOUND_MASK_PHONEIN, (int *)arg); - - case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ - return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO | - SOUND_MASK_LINE1 | SOUND_MASK_PCM | SOUND_MASK_VOLUME | - SOUND_MASK_PHONEOUT | SOUND_MASK_RECLEV, (int *)arg); - - case SOUND_MIXER_CAPS: - return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES) - return -EINVAL; -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - return mixer_rdch(s, i, (int *)arg); -#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - if (!volidx[i]) - return -EINVAL; - return put_user(s->mix.vol[volidx[i]-1], (int *)arg); -#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - } - } - if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) - return -EINVAL; - s->mix.modcnt++; - switch (_IOC_NR(cmd)) { - case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ - get_user_ret(val, (int *)arg, -EFAULT); - i = hweight32(val); - if (i == 0) - return 0; /*val = mixer_recmask(s);*/ - else if (i > 1) - val &= ~recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7]; - for (i = 0; i < 8; i++) { - if (val & recsrc[i]) { - wrcodec(s, AC97_RECORD_SELECT, 0x101 * i); - return 0; - } - } - return 0; - - default: - i = _IOC_NR(cmd); - if (i >= SOUND_MIXER_NRDEVICES) - return -EINVAL; - get_user_ret(val, (int *)arg, -EFAULT); - if (mixer_wrch(s, i, val)) - return -EINVAL; -#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS - return mixer_rdch(s, i, (int *)arg); -#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - if (!volidx[i]) - return -EINVAL; - s->mix.vol[volidx[i]-1] = val; - return put_user(s->mix.vol[volidx[i]-1], (int *)arg); -#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ - } -} - -/* --------------------------------------------------------------------- */ - -static loff_t es1371_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - -/* --------------------------------------------------------------------- */ - static int es1371_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct es1371_state *s = devs; + struct list_head *list; + struct es1371_state *s; - while (s && s->dev_mixer != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct es1371_state, devs); + if (s->codec.dev_mixer == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; MOD_INC_USE_COUNT; @@ -1618,23 +1177,15 @@ static int es1371_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return mixer_ioctl((struct es1371_state *)file->private_data, cmd, arg); + struct ac97_codec *codec = &((struct es1371_state *)file->private_data)->codec; + return codec->mixer_ioctl(codec, cmd, arg); } static /*const*/ struct file_operations es1371_mixer_fops = { - &es1371_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &es1371_ioctl_mixdev, - NULL, /* mmap */ - &es1371_open_mixdev, - NULL, /* flush */ - &es1371_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: es1371_llseek, + ioctl: es1371_ioctl_mixdev, + open: es1371_open_mixdev, + release: es1371_release_mixdev, }; /* --------------------------------------------------------------------- */ @@ -2223,20 +1774,24 @@ return -EINVAL; } - return mixer_ioctl(s, cmd, arg); + return s->codec.mixer_ioctl(&s->codec, cmd, arg); } static int es1371_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct es1371_state *s = devs; unsigned long flags; + struct list_head *list; + struct es1371_state *s; - while (s && ((s->dev_audio ^ minor) & ~0xf)) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct es1371_state, devs); + if (!((s->dev_audio ^ minor) & ~0xf)) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -2297,11 +1852,11 @@ down(&s->open_sem); if (file->f_mode & FMODE_WRITE) { stop_dac2(s); - dealloc_dmabuf(&s->dma_dac2); + dealloc_dmabuf(s, &s->dma_dac2); } if (file->f_mode & FMODE_READ) { stop_adc(s); - dealloc_dmabuf(&s->dma_adc); + dealloc_dmabuf(s, &s->dma_adc); } s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); up(&s->open_sem); @@ -2311,19 +1866,14 @@ } static /*const*/ struct file_operations es1371_audio_fops = { - &es1371_llseek, - &es1371_read, - &es1371_write, - NULL, /* readdir */ - &es1371_poll, - &es1371_ioctl, - &es1371_mmap, - &es1371_open, - NULL, /* flush */ - &es1371_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: es1371_llseek, + read: es1371_read, + write: es1371_write, + poll: es1371_poll, + ioctl: es1371_ioctl, + mmap: es1371_mmap, + open: es1371_open, + release: es1371_release, }; /* --------------------------------------------------------------------- */ @@ -2626,20 +2176,24 @@ return -EINVAL; } - return mixer_ioctl(s, cmd, arg); + return s->codec.mixer_ioctl(&s->codec, cmd, arg); } static int es1371_open_dac(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct es1371_state *s = devs; unsigned long flags; + struct list_head *list; + struct es1371_state *s; - while (s && ((s->dev_dac ^ minor) & ~0xf)) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct es1371_state, devs); + if (!((s->dev_dac ^ minor) & ~0xf)) + break; + } VALIDATE_STATE(s); /* we allow opening with O_RDWR, most programs do it although they will only write */ #if 0 @@ -2690,7 +2244,7 @@ drain_dac1(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); stop_dac1(s); - dealloc_dmabuf(&s->dma_dac1); + dealloc_dmabuf(s, &s->dma_dac1); s->open_mode &= ~FMODE_DAC; up(&s->open_sem); wake_up(&s->open_wait); @@ -2699,19 +2253,13 @@ } static /*const*/ struct file_operations es1371_dac_fops = { - &es1371_llseek, - NULL, /* read */ - &es1371_write_dac, - NULL, /* readdir */ - &es1371_poll_dac, - &es1371_ioctl_dac, - &es1371_mmap_dac, - &es1371_open_dac, - NULL, /* flush */ - &es1371_release_dac, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: es1371_llseek, + write: es1371_write_dac, + poll: es1371_poll_dac, + ioctl: es1371_ioctl_dac, + mmap: es1371_mmap_dac, + open: es1371_open_dac, + release: es1371_release_dac, }; /* --------------------------------------------------------------------- */ @@ -2874,13 +2422,17 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct es1371_state *s = devs; unsigned long flags; + struct list_head *list; + struct es1371_state *s; - while (s && s->dev_midi != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct es1371_state, devs); + if (s->dev_midi == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -2970,45 +2522,38 @@ } static /*const*/ struct file_operations es1371_midi_fops = { - &es1371_llseek, - &es1371_midi_read, - &es1371_midi_write, - NULL, /* readdir */ - &es1371_midi_poll, - NULL, /* ioctl */ - NULL, /* mmap */ - &es1371_midi_open, - NULL, /* flush */ - &es1371_midi_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: es1371_llseek, + read: es1371_midi_read, + write: es1371_midi_write, + poll: es1371_midi_poll, + open: es1371_midi_open, + release: es1371_midi_release, }; /* --------------------------------------------------------------------- */ /* * for debugging purposes, we'll create a proc device that dumps the - * CODEC chipstate + * CODEC chipstate */ #ifdef ES1371_DEBUG static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data) { - int len = 0; - - struct es1371_state *s = devs; - int cnt; + struct es1371_state *s; + int cnt, len = 0; + if (list_empty(&devs)) + return 0; + s = list_entry(devs.next, struct es1371_state, devs); /* print out header */ len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n"); /* print out CODEC state */ len += sprintf (buf + len, "AC97 CODEC state\n"); - - for (cnt=0; cnt <= 0x7e; cnt = cnt +2) - len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(s , cnt)); - + for (cnt=0; cnt <= 0x7e; cnt = cnt +2) + len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(&s->codec, cnt)); + if (fpos >=len){ *start = buf; *eof =1; @@ -3025,12 +2570,14 @@ /* --------------------------------------------------------------------- */ -/* maximum number of devices */ +/* maximum number of devices; only used for command line params */ #define NR_DEVICE 5 static int joystick[NR_DEVICE] = { 0, }; static int spdif[NR_DEVICE] = { 0, }; +static unsigned int devindex = 0; + MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i"); MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)"); MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i"); @@ -3064,12 +2611,11 @@ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int __init probe_chip(struct pci_dev *pcidev, int index) +static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct es1371_state *s; mm_segment_t fs; - int i, val, val2; - unsigned char id[4]; + int i, val; unsigned long tmo; signed long tmo2; unsigned int cssr; @@ -3092,28 +2638,33 @@ init_MUTEX(&s->open_sem); spin_lock_init(&s->lock); s->magic = ES1371_MAGIC; + s->dev = pcidev; s->io = RSRCADDRESS(pcidev, 0); s->irq = pcidev->irq; s->vendor = pcidev->vendor; s->device = pcidev->device; pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev); + s->codec.private_data = s; + s->codec.id = 0; + s->codec.codec_read = rdcodec; + s->codec.codec_write = wrcodec; printk(KERN_INFO "es1371: found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n", s->vendor, s->device, s->rev); - if (check_region(s->io, ES1371_EXTENT)) { + if (!request_region(s->io, ES1371_EXTENT, "es1371")) { printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); goto err_region; } - request_region(s->io, ES1371_EXTENT, "es1371"); if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) { printk(KERN_ERR "es1371: irq %u in use\n", s->irq); goto err_irq; } + pci_enable_device(pcidev); printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n" - KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[index]); + KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]); /* register devices */ if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) goto err_dev1; - if ((s->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0) + if ((s->codec.dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0) goto err_dev2; if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0) goto err_dev3; @@ -3126,17 +2677,17 @@ /* initialize codec registers */ s->ctrl = 0; - if ((joystick[index] & ~0x18) == 0x200) { - if (check_region(joystick[index], JOY_EXTENT)) - printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[index]); + if ((joystick[devindex] & ~0x18) == 0x200) { + if (check_region(joystick[devindex], JOY_EXTENT)) + printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[devindex]); else { - s->ctrl |= CTRL_JYSTK_EN | (((joystick[index] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); + s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); } } s->sctrl = 0; cssr = 0; /* check to see if s/pdif mode is being requested */ - if (spdif[index]) { + if (spdif[devindex]) { if (s->rev >= 4) { printk(KERN_INFO "es1371: enabling S/PDIF output\n"); cssr |= STAT_EN_SPDIF; @@ -3173,68 +2724,34 @@ /* init the sample rate converter */ src_init(s); /* codec init */ - wrcodec(s, AC97_RESET, 0); /* reset codec */ - s->mix.codec_id = rdcodec(s, AC97_RESET); /* get codec ID */ - val = rdcodec(s, AC97_VENDOR_ID1); - val2 = rdcodec(s, AC97_VENDOR_ID2); - id[0] = val >> 8; - id[1] = val; - id[2] = val2 >> 8; - id[3] = 0; - if (id[0] <= ' ' || id[0] > 0x7f) - id[0] = ' '; - if (id[1] <= ' ' || id[1] > 0x7f) - id[1] = ' '; - if (id[2] <= ' ' || id[2] > 0x7f) - id[2] = ' '; - printk(KERN_INFO "es1371: codec vendor %s (0x%04x%02x) revision %d (0x%02x)\n", - id, val & 0xffff, (val2 >> 8) & 0xff, val2 & 0xff, val2 & 0xff); - printk(KERN_INFO "es1371: codec features"); - if (s->mix.codec_id & CODEC_ID_DEDICATEDMIC) - printk(" dedicated MIC PCM in"); - if (s->mix.codec_id & CODEC_ID_MODEMCODEC) - printk(" Modem Line Codec"); - if (s->mix.codec_id & CODEC_ID_BASSTREBLE) - printk(" Bass & Treble"); - if (s->mix.codec_id & CODEC_ID_SIMULATEDSTEREO) - printk(" Simulated Stereo"); - if (s->mix.codec_id & CODEC_ID_HEADPHONEOUT) - printk(" Headphone out"); - if (s->mix.codec_id & CODEC_ID_LOUDNESS) - printk(" Loudness"); - if (s->mix.codec_id & CODEC_ID_18BITDAC) - printk(" 18bit DAC"); - if (s->mix.codec_id & CODEC_ID_20BITDAC) - printk(" 20bit DAC"); - if (s->mix.codec_id & CODEC_ID_18BITADC) - printk(" 18bit ADC"); - if (s->mix.codec_id & CODEC_ID_20BITADC) - printk(" 20bit ADC"); - printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none"); - val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK; - printk(KERN_INFO "es1371: stereo enhancement: %s\n", - (val <= 26 && stereo_enhancement[val]) ? stereo_enhancement[val] : "unknown"); - + if (!ac97_probe_codec(&s->codec)) + goto err_dev4; + /* set default values */ fs = get_fs(); set_fs(KERNEL_DS); val = SOUND_MASK_LINE; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); + s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); + s->codec.mixer_ioctl(&s->codec, initvol[i].mixch, (unsigned long)&val); } set_fs(fs); /* turn on S/PDIF output driver if requested */ outl(cssr, s->io+ES1371_REG_STATUS); - /* queue it for later freeing */ - s->next = devs; - devs = s; + /* store it in the driver field */ + pcidev->driver_data = s; + pcidev->dma_mask = 0xffffffff; + /* put it into driver list */ + list_add_tail(&s->devs, &devs); + /* increment devindex */ + if (devindex < NR_DEVICE-1) + devindex++; return 0; err_dev4: unregister_sound_dsp(s->dev_dac); err_dev3: - unregister_sound_mixer(s->dev_mixer); + unregister_sound_mixer(s->codec.dev_mixer); err_dev2: unregister_sound_dsp(s->dev_audio); err_dev1: @@ -3247,55 +2764,60 @@ return -1; } +static void es1371_remove(struct pci_dev *dev) +{ + struct es1371_state *s = (struct es1371_state *)dev->driver_data; + + if (!s) + return; + list_del(&s->devs); +#ifdef ES1371_DEBUG + if (s->ps) + remove_proc_entry("es1371", NULL); +#endif /* ES1371_DEBUG */ + outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */ + outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */ + synchronize_irq(); + free_irq(s->irq, s); + release_region(s->io, ES1371_EXTENT); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->codec.dev_mixer); + unregister_sound_dsp(s->dev_dac); + unregister_sound_midi(s->dev_midi); + kfree_s(s, sizeof(struct es1371_state)); + dev->driver_data = NULL; +} + +static const struct pci_device_id id_table[] = { + { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, + { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, + { PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +MODULE_DEVICE_TABLE(pci, id_table); + +static struct pci_driver es1371_driver = { + name: "es1371", + id_table: id_table, + probe: es1371_probe, + remove: es1371_remove +}; static int __init init_es1371(void) { - struct pci_dev *pcidev = NULL; - int index = 0; - if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.23 time " __TIME__ " " __DATE__ "\n"); - while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pcidev))) { - if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) { - if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 && - pcidev->device != PCI_DEVICE_ID_ENSONIQ_CT5880) - continue; - } else if (pcidev->vendor == PCI_VENDOR_ID_ECTIVA) { - if (pcidev->device != PCI_DEVICE_ID_ECTIVA_EV1938) - continue; - } else - continue; - if (!probe_chip(pcidev, index)) - index++; - } - if (!devs) + printk(KERN_INFO "es1371: version v0.25 time " __TIME__ " " __DATE__ "\n"); + if (!pci_register_driver(&es1371_driver)) return -ENODEV; return 0; } static void __exit cleanup_es1371(void) { - struct es1371_state *s; - - while ((s = devs)) { - devs = devs->next; -#ifdef ES1371_DEBUG - if (s->ps) - remove_proc_entry("es1371", NULL); -#endif /* ES1371_DEBUG */ - outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */ - outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */ - synchronize_irq(); - free_irq(s->irq, s); - release_region(s->io, ES1371_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_dsp(s->dev_dac); - unregister_sound_midi(s->dev_midi); - kfree_s(s, sizeof(struct es1371_state)); - } printk(KERN_INFO "es1371: unloading\n"); + pci_unregister_driver(&es1371_driver); } module_init(init_es1371); diff -u --recursive --new-file v2.3.42/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.3.42/linux/drivers/sound/esssolo1.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sound/esssolo1.c Wed Feb 9 11:42:35 2000 @@ -66,12 +66,12 @@ * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun; * Tim Janik's BSE (Bedevilled Sound Engine) found this * Integrated (aka redid 8-)) APM support patch by Zach Brown + * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver * */ /*****************************************************************************/ -#include #include #include #include @@ -83,7 +83,7 @@ #include #include #include -#include +#include #include #include #include @@ -137,11 +137,11 @@ /* magic */ unsigned int magic; - /* we keep the cards in a linked list */ - struct solo1_state *next; + /* list of esssolo1 devices */ + struct list_head devs; - /* pcidev is needed to turn off the DDMA controller at driver shutdown */ - struct pci_dev *pcidev; + /* the corresponding pci_dev structure */ + struct pci_dev *dev; /* soundcore stuff */ int dev_audio; @@ -175,6 +175,7 @@ struct dmabuf { void *rawbuf; + dma_addr_t dmaaddr; unsigned buforder; unsigned numfrag; unsigned fragshift; @@ -210,7 +211,7 @@ /* --------------------------------------------------------------------- */ -struct solo1_state *devs = NULL; +static LIST_HEAD(devs); /* --------------------------------------------------------------------- */ @@ -396,7 +397,7 @@ #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) #define DMABUF_MINORDER 1 -extern inline void dealloc_dmabuf(struct dmabuf *db) +extern inline void dealloc_dmabuf(struct solo1_state *s, struct dmabuf *db) { unsigned long map, mapend; @@ -405,13 +406,13 @@ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (map = MAP_NR(db->rawbuf); map <= mapend; map++) clear_bit(PG_reserved, &mem_map[map].flags); - free_pages((unsigned long)db->rawbuf, db->buforder); + pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); } db->rawbuf = NULL; db->mapped = db->ready = 0; } -static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, int gfp_mask) +static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, unsigned long dmamask) { int order; unsigned bytespersec; @@ -421,19 +422,12 @@ db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; if (!db->rawbuf) { db->ready = db->mapped = 0; + s->dev->dma_mask = dmamask; for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = (void *)__get_free_pages(gfp_mask, order))) + if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) break; if (!db->rawbuf) return -ENOMEM; - /* work around a problem of the alpha port */ - if ((gfp_mask & GFP_DMA) && (virt_to_bus(db->rawbuf) & (~0xffffffUL))) { - printk(KERN_ERR "solo1: requested DMA buffer below 16M but got 0x%lx, Alpha bug?\n", - (unsigned long)virt_to_bus(db->rawbuf)); - kfree(db->rawbuf); - db->rawbuf = NULL; - return -ENOMEM; - } db->buforder = order; /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); @@ -475,9 +469,9 @@ int c; stop_adc(s); - if ((c = prog_dmabuf(s, &s->dma_adc, GFP_KERNEL | GFP_DMA))) + if ((c = prog_dmabuf(s, &s->dma_adc, 0xffffff))) return c; - va = virt_to_bus(s->dma_adc.rawbuf); + va = s->dma_adc.dmaaddr; if ((va & ~((1<<24)-1))) panic("solo1: buffer above 16M boundary"); outb(0, s->ddmabase+0xd); /* clear */ @@ -500,10 +494,10 @@ int c; stop_dac(s); - if ((c = prog_dmabuf(s, &s->dma_dac, GFP_KERNEL))) + if ((c = prog_dmabuf(s, &s->dma_dac, 0xffffffff))) return c; memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */ - va = virt_to_bus(s->dma_dac.rawbuf); + va = s->dma_dac.dmaaddr; if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1)) panic("solo1: buffer crosses 1M boundary"); outl(va, s->iobase); @@ -900,12 +894,16 @@ static int solo1_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct solo1_state *s = devs; + struct list_head *list; + struct solo1_state *s; - while (s && s->dev_mixer != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct solo1_state, devs); + if (s->dev_mixer == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; MOD_INC_USE_COUNT; @@ -915,7 +913,7 @@ static int solo1_release_mixdev(struct inode *inode, struct file *file) { struct solo1_state *s = (struct solo1_state *)file->private_data; - + VALIDATE_STATE(s); MOD_DEC_USE_COUNT; return 0; @@ -927,19 +925,10 @@ } static /*const*/ struct file_operations solo1_mixer_fops = { - &solo1_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &solo1_ioctl_mixdev, - NULL, /* mmap */ - &solo1_open_mixdev, - NULL, /* flush */ - &solo1_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: solo1_llseek, + ioctl: solo1_ioctl_mixdev, + open: solo1_open_mixdev, + release: solo1_release_mixdev, }; /* --------------------------------------------------------------------- */ @@ -1522,13 +1511,13 @@ if (file->f_mode & FMODE_WRITE) { stop_dac(s); outb(0, s->iobase+6); /* disable DMA */ - dealloc_dmabuf(&s->dma_dac); + dealloc_dmabuf(s, &s->dma_dac); } if (file->f_mode & FMODE_READ) { stop_adc(s); outb(1, s->ddmabase+0xf); /* mask DMA channel */ outb(0, s->ddmabase+0xd); /* DMA master clear */ - dealloc_dmabuf(&s->dma_adc); + dealloc_dmabuf(s, &s->dma_adc); } s->open_mode &= ~(FMODE_READ | FMODE_WRITE); wake_up(&s->open_wait); @@ -1541,12 +1530,16 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct solo1_state *s = devs; - - while (s && ((s->dev_audio ^ minor) & ~0xf)) - s = s->next; - if (!s) - return -ENODEV; + struct list_head *list; + struct solo1_state *s; + + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct solo1_state, devs); + if (!((s->dev_audio ^ minor) & ~0xf)) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -1581,19 +1574,14 @@ } static /*const*/ struct file_operations solo1_audio_fops = { - &solo1_llseek, - &solo1_read, - &solo1_write, - NULL, /* readdir */ - &solo1_poll, - &solo1_ioctl, - &solo1_mmap, - &solo1_open, - NULL, /* flush */ - &solo1_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: solo1_llseek, + read: solo1_read, + write: solo1_write, + poll: solo1_poll, + ioctl: solo1_ioctl, + mmap: solo1_mmap, + open: solo1_open, + release: solo1_release, }; /* --------------------------------------------------------------------- */ @@ -1821,13 +1809,17 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct solo1_state *s = devs; unsigned long flags; + struct list_head *list; + struct solo1_state *s; - while (s && s->dev_midi != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct solo1_state, devs); + if (s->dev_midi == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -1923,19 +1915,12 @@ } static /*const*/ struct file_operations solo1_midi_fops = { - &solo1_llseek, - &solo1_midi_read, - &solo1_midi_write, - NULL, /* readdir */ - &solo1_midi_poll, - NULL, /* ioctl */ - NULL, /* mmap */ - &solo1_midi_open, - NULL, /* flush */ - &solo1_midi_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: solo1_llseek, + read: solo1_midi_read, + write: solo1_midi_write, + poll: solo1_midi_poll, + open: solo1_midi_open, + release: solo1_midi_release, }; /* --------------------------------------------------------------------- */ @@ -2041,12 +2026,16 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct solo1_state *s = devs; + struct list_head *list; + struct solo1_state *s; - while (s && s->dev_dmfm != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct solo1_state, devs); + if (s->dev_dmfm == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -2107,28 +2096,14 @@ } static /*const*/ struct file_operations solo1_dmfm_fops = { - &solo1_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &solo1_dmfm_ioctl, - NULL, /* mmap */ - &solo1_dmfm_open, - NULL, /* flush */ - &solo1_dmfm_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: solo1_llseek, + ioctl: solo1_dmfm_ioctl, + open: solo1_dmfm_open, + release: solo1_dmfm_release, }; /* --------------------------------------------------------------------- */ -/* maximum number of devices */ -#define NR_DEVICE 5 - -/* --------------------------------------------------------------------- */ - static struct initvol { int mixch; int vol; @@ -2147,7 +2122,7 @@ static int setup_solo1(struct solo1_state *s) { - struct pci_dev *pcidev = s->pcidev; + struct pci_dev *pcidev = s->dev; mm_segment_t fs; int i, val; @@ -2187,141 +2162,185 @@ return 0; } -#ifdef CONFIG_APM - -static int solo1_apm_callback(apm_event_t event) +static int solo1_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) { - struct solo1_state *s; - - switch(event) { - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - case APM_STANDBY_RESUME: - for(s = devs ; s ; s = s->next) + struct solo1_state *s = (struct solo1_state*) dev->data; + if (s) { + switch(rqst) { + case PM_RESUME: setup_solo1(s); - break; + break; - default: - for(s = devs ; s ; s = s->next) { - 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->pcidev, 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; } -#endif - #define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) - -static int __init init_solo1(void) +static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct solo1_state *s; - struct pci_dev *pcidev = NULL; - int index = 0; + struct pm_dev *pmdev; - if (!pci_present()) /* No PCI bus in this machine! */ - return -ENODEV; - printk(KERN_INFO "solo1: version v0.12 time " __TIME__ " " __DATE__ "\n"); - while (index < NR_DEVICE && - (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) { - if (!RSRCISIOREGION(pcidev, 0) || - !RSRCISIOREGION(pcidev, 1) || - !RSRCISIOREGION(pcidev, 2) || - !RSRCISIOREGION(pcidev, 3)) - continue; - if (pcidev->irq == 0) - continue; - if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) { - printk(KERN_WARNING "solo1: out of memory\n"); - continue; - } - memset(s, 0, sizeof(struct solo1_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - init_MUTEX(&s->open_sem); - spin_lock_init(&s->lock); - s->magic = SOLO1_MAGIC; - s->pcidev = pcidev; - s->iobase = RSRCADDRESS(pcidev, 0); - s->sbbase = RSRCADDRESS(pcidev, 1); - s->vcbase = RSRCADDRESS(pcidev, 2); - s->ddmabase = s->vcbase + DDMABASE_OFFSET; - s->mpubase = RSRCADDRESS(pcidev, 3); - s->gpbase = RSRCADDRESS(pcidev, 4); - s->irq = pcidev->irq; - if (check_region(s->iobase, IOBASE_EXTENT) || - check_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT) || - check_region(s->ddmabase, DDMABASE_EXTENT) || - check_region(s->mpubase, MPUBASE_EXTENT)) { - printk(KERN_ERR "solo1: io ports in use\n"); - goto err_region; - } - request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1"); - request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1"); - request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1"); - request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1"); - if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) { - printk(KERN_ERR "solo1: irq %u in use\n", s->irq); - goto err_irq; - } - printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase); - - printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1); - - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) - goto err_dev2; - if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) - goto err_dev3; - if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) - goto err_dev4; - if (setup_solo1(s)) - goto err; - /* queue it for later freeing */ - s->next = devs; - devs = s; - index++; - continue; - - err: - unregister_sound_dsp(s->dev_dmfm); - err_dev4: - unregister_sound_dsp(s->dev_midi); - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR "solo1: initialisation error\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->iobase, IOBASE_EXTENT); - release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); - release_region(s->ddmabase, DDMABASE_EXTENT); - release_region(s->mpubase, MPUBASE_EXTENT); - err_region: - kfree_s(s, sizeof(struct solo1_state)); + if (!RSRCISIOREGION(pcidev, 0) || + !RSRCISIOREGION(pcidev, 1) || + !RSRCISIOREGION(pcidev, 2) || + !RSRCISIOREGION(pcidev, 3)) + return -1; + if (pcidev->irq == 0) + return -1; + if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) { + printk(KERN_WARNING "solo1: out of memory\n"); + return -1; } - if (!devs) + memset(s, 0, sizeof(struct solo1_state)); + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->midi.iwait); + init_waitqueue_head(&s->midi.owait); + init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); + s->magic = SOLO1_MAGIC; + s->dev = pcidev; + s->iobase = RSRCADDRESS(pcidev, 0); + s->sbbase = RSRCADDRESS(pcidev, 1); + s->vcbase = RSRCADDRESS(pcidev, 2); + s->ddmabase = s->vcbase + DDMABASE_OFFSET; + s->mpubase = RSRCADDRESS(pcidev, 3); + s->gpbase = RSRCADDRESS(pcidev, 4); + s->irq = pcidev->irq; + if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) { + printk(KERN_ERR "solo1: io ports in use\n"); + goto err_region1; + } + if (!request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1")) { + printk(KERN_ERR "solo1: io ports in use\n"); + goto err_region2; + } + if (!request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1")) { + printk(KERN_ERR "solo1: io ports in use\n"); + goto err_region3; + } + if (!request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1")) { + printk(KERN_ERR "solo1: io ports in use\n"); + goto err_region4; + } + if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) { + printk(KERN_ERR "solo1: irq %u in use\n", s->irq); + goto err_irq; + } + pci_enable_device(pcidev); + printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase); + printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) + goto err_dev1; + if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) + goto err_dev2; + if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) + goto err_dev3; + if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) + goto err_dev4; + if (setup_solo1(s)) + goto err; + /* store it in the driver field */ + pcidev->driver_data = s; + pcidev->dma_mask = 0xffffff; /* pessimistic; play can handle 32bit addrs */ + /* 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: + unregister_sound_dsp(s->dev_dmfm); + err_dev4: + unregister_sound_dsp(s->dev_midi); + err_dev3: + unregister_sound_mixer(s->dev_mixer); + err_dev2: + unregister_sound_dsp(s->dev_audio); + err_dev1: + printk(KERN_ERR "solo1: initialisation error\n"); + free_irq(s->irq, s); + err_irq: + release_region(s->iobase, IOBASE_EXTENT); + err_region4: + release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); + err_region3: + release_region(s->ddmabase, DDMABASE_EXTENT); + err_region2: + release_region(s->mpubase, MPUBASE_EXTENT); + err_region1: + kfree_s(s, sizeof(struct solo1_state)); + return -1; +} + +static void solo1_remove(struct pci_dev *dev) +{ + struct solo1_state *s = (struct solo1_state *)dev->driver_data; + + if (!s) + return; + list_del(&s->devs); + /* stop DMA controller */ + outb(0, s->iobase+6); + outb(0, s->ddmabase+0xd); /* DMA master clear */ + outb(3, s->sbbase+6); /* reset sequencer and FIFO */ + synchronize_irq(); + pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */ + free_irq(s->irq, s); + release_region(s->iobase, IOBASE_EXTENT); + release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); + release_region(s->ddmabase, DDMABASE_EXTENT); + release_region(s->mpubase, MPUBASE_EXTENT); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->dev_mixer); + unregister_sound_midi(s->dev_midi); + unregister_sound_special(s->dev_dmfm); + kfree_s(s, sizeof(struct solo1_state)); + dev->driver_data = NULL; +} + +static const struct pci_device_id id_table[] = { + { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +MODULE_DEVICE_TABLE(pci, id_table); + +static struct pci_driver solo1_driver = { + name: "ESS Solo1", + id_table: id_table, + probe: solo1_probe, + remove: solo1_remove +}; + + +static int __init init_solo1(void) +{ + if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; -#ifdef CONFIG_APM - apm_register_callback(solo1_apm_callback); -#endif + printk(KERN_INFO "solo1: version v0.13 time " __TIME__ " " __DATE__ "\n"); + if (!pci_register_driver(&solo1_driver)) + return -ENODEV; return 0; } @@ -2332,31 +2351,9 @@ static void __exit cleanup_solo1(void) { - struct solo1_state *s; - - while ((s = devs)) { - devs = devs->next; - /* stop DMA controller */ - outb(0, s->iobase+6); - outb(0, s->ddmabase+0xd); /* DMA master clear */ - outb(3, s->sbbase+6); /* reset sequencer and FIFO */ - synchronize_irq(); - pci_write_config_word(s->pcidev, 0x60, 0); /* turn off DDMA controller address space */ - free_irq(s->irq, s); - release_region(s->iobase, IOBASE_EXTENT); - release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT); - release_region(s->ddmabase, DDMABASE_EXTENT); - release_region(s->mpubase, MPUBASE_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_midi(s->dev_midi); - unregister_sound_special(s->dev_dmfm); - kfree_s(s, sizeof(struct solo1_state)); - } -#ifdef CONFIG_APM - apm_unregister_callback(solo1_apm_callback); -#endif printk(KERN_INFO "solo1: unloading\n"); + pci_unregister_driver(&solo1_driver); + pm_unregister_all(solo1_pm_callback); } /* --------------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.42/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.3.42/linux/drivers/sound/maestro.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sound/maestro.c Wed Feb 9 11:42:35 2000 @@ -177,7 +177,6 @@ /*****************************************************************************/ -#include #include #include @@ -217,16 +216,12 @@ #include #include -#ifdef CONFIG_APM -#include -static int maestro_apm_callback(apm_event_t ae); +#include +static int maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *d); static int in_suspend=0; wait_queue_head_t suspend_queue; static void check_suspend(void); #define CHECK_SUSPEND check_suspend(); -#else -#define CHECK_SUSPEND -#endif #include "maestro.h" @@ -390,11 +385,9 @@ struct ess_state channels[MAX_DSPS]; u16 maestro_map[NR_IDRS]; /* Register map */ -#ifdef CONFIG_APM /* we have to store this junk so that we can come back from a suspend */ u16 apu_map[NR_APUS][NR_APU_REGS]; /* contents of apu regs */ -#endif /* this locks around the physical registers on the card */ spinlock_t lock; @@ -1020,10 +1013,8 @@ printk("BAD CHANNEL %d.\n",channel); else channel = s->apu[channel]; -#ifdef CONFIG_APM /* store based on real hardware apu/reg */ s->card->apu_map[channel][reg]=data; -#endif } reg|=(channel<<4); @@ -2032,19 +2023,10 @@ } static /*const*/ struct file_operations ess_mixer_fops = { - &ess_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &ess_ioctl_mixdev, - NULL, /* mmap */ - &ess_open_mixdev, - NULL, /* flush */ - &ess_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: ess_llseek, + ioctl: ess_ioctl_mixdev, + open: ess_open_mixdev, + release: ess_release_mixdev, }; /* --------------------------------------------------------------------- */ @@ -2171,9 +2153,7 @@ goto rec_return_free; } if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { -#ifdef CONFIG_APM if(! in_suspend) -#endif printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, s->dma_adc.hwptr, s->dma_adc.swptr); @@ -2273,9 +2253,7 @@ goto return_free; } if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { -#ifdef CONFIG_APM if(! in_suspend) -#endif printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr, s->dma_dac.swptr); @@ -2906,19 +2884,14 @@ } static struct file_operations ess_audio_fops = { - &ess_llseek, - &ess_read, - &ess_write, - NULL, /* readdir */ - &ess_poll, - &ess_ioctl, - &ess_mmap, - &ess_open, - NULL, /* flush */ - &ess_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: ess_llseek, + read: ess_read, + write: ess_write, + poll: ess_poll, + ioctl: ess_ioctl, + mmap: ess_mmap, + open: ess_open, + release: ess_release, }; static int @@ -3176,6 +3149,7 @@ int i; struct ess_card *card; struct ess_state *ess; + struct pm_dev *pmdev; int num = 0; /* don't pick up weird modem maestros */ @@ -3209,11 +3183,11 @@ memset(card, 0, sizeof(*card)); memcpy(&card->pcidev,pcidev,sizeof(card->pcidev)); -#ifdef CONFIG_APM - if (apm_register_callback(maestro_apm_callback)) { - printk(KERN_WARNING "maestro: apm suspend might not work.\n"); - } -#endif + pmdev = pm_register(PM_PCI_DEV, + PM_PCI_ID(pcidev), + maestro_pm_callback); + if (pmdev) + pmdev->data = card; card->iobase = iobase; card->card_type = card_type; @@ -3331,9 +3305,7 @@ printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order); } -#ifdef CONFIG_APM init_waitqueue_head(&suspend_queue); -#endif /* * Find the ESS Maestro 2. @@ -3382,9 +3354,8 @@ { struct ess_card *s; -#ifdef CONFIG_APM - apm_unregister_callback(maestro_apm_callback); -#endif + pm_unregister_all(maestro_pm_callback); + while ((s = devs)) { int i; devs = devs->next; @@ -3406,7 +3377,6 @@ } #endif /* MODULE */ -#ifdef CONFIG_APM void check_suspend(void) @@ -3424,38 +3394,35 @@ } static int -maestro_suspend(void) +maestro_suspend(struct ess_card *card) { - struct ess_card *card; unsigned long flags; + int i,j; save_flags(flags); cli(); - for (card = devs; card ; card = card->next) { - int i,j; - - M_printk("maestro: apm in dev %p\n",card); + M_printk("maestro: pm in dev %p\n",card); - for(i=0;ichannels[i]; + for(i=0;ichannels[i]; - if(s->dev_audio == -1) - continue; + if(s->dev_audio == -1) + continue; + + M_printk("maestro: stopping apus for device %d\n",i); + stop_dac(s); + stop_adc(s); + for(j=0;j<6;j++) + card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5); + + } - M_printk("maestro: stopping apus for device %d\n",i); - stop_dac(s); - stop_adc(s); - for(j=0;j<6;j++) - card->apu_map[s->apu[j]][5]=apu_get_register(s,j,5); + /* get rid of interrupts? */ + if( card->dsps_open > 0) + stop_bob(&card->channels[0]); - } - - /* get rid of interrupts? */ - if( card->dsps_open > 0) - stop_bob(&card->channels[0]); - } - in_suspend=1; + in_suspend=1; restore_flags(flags); @@ -3464,10 +3431,10 @@ return 0; } static int -maestro_resume(void) +maestro_resume(struct ess_card *card) { - struct ess_card *card; unsigned long flags; + int i; save_flags(flags); cli(); @@ -3475,52 +3442,45 @@ M_printk("maestro: resuming\n"); /* first lets just bring everything back. .*/ - for (card = devs; card ; card = card->next) { - int i; - M_printk("maestro: apm in dev %p\n",card); - - maestro_config(card); - /* need to restore the base pointers.. */ - if(card->dmapages) - set_base_registers(&card->channels[0],card->dmapages); - - mixer_push_state(card); + M_printk("maestro: pm in dev %p\n",card); - for(i=0;ichannels[i]; - int chan,reg; - - if(s->dev_audio == -1) - continue; - - for(chan = 0 ; chan < 6 ; chan++) { - wave_set_register(s,s->apu[chan]<<3,s->apu_base[chan]); - for(reg = 1 ; reg < NR_APU_REGS ; reg++) - apu_set_register(s,chan,reg,s->card->apu_map[s->apu[chan]][reg]); - } - for(chan = 0 ; chan < 6 ; chan++) - apu_set_register(s,chan,0,s->card->apu_map[s->apu[chan]][0] & 0xFF0F); - } - } + maestro_config(card); + /* need to restore the base pointers.. */ + if(card->dmapages) + set_base_registers(&card->channels[0],card->dmapages); + + mixer_push_state(card); + + for(i=0;ichannels[i]; + int chan,reg; + + if(s->dev_audio == -1) + continue; + + for(chan = 0 ; chan < 6 ; chan++) { + wave_set_register(s,s->apu[chan]<<3,s->apu_base[chan]); + for(reg = 1 ; reg < NR_APU_REGS ; reg++) + apu_set_register(s,chan,reg,s->card->apu_map[s->apu[chan]][reg]); + } + for(chan = 0 ; chan < 6 ; chan++) + apu_set_register(s,chan,0,s->card->apu_map[s->apu[chan]][0] & 0xFF0F); + } /* now we flip on the music */ - for (card = devs; card ; card = card->next) { - int i; - - M_printk("maestro: apm in dev %p\n",card); - - for(i=0;ichannels[i]; + M_printk("maestro: pm in dev %p\n",card); - /* these use the apu_mode, and can handle - spurious calls */ - start_dac(s); - start_adc(s); - } - if( card->dsps_open > 0) - start_bob(&card->channels[0]); - } + for(i=0;ichannels[i]; + + /* these use the apu_mode, and can handle + spurious calls */ + start_dac(s); + start_adc(s); + } + if( card->dsps_open > 0) + start_bob(&card->channels[0]); restore_flags(flags); @@ -3530,22 +3490,20 @@ } int -maestro_apm_callback(apm_event_t ae) { - - M_printk("maestro: apm event received: 0x%x\n",ae); - - switch(ae) { - case APM_SYS_SUSPEND: - case APM_CRITICAL_SUSPEND: - case APM_USER_SUSPEND: - maestro_suspend();break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - case APM_STANDBY_RESUME: - maestro_resume();break; - default: break; - } +maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) { + struct ess_card *card = (struct ess_card*) dev->data; + if (card) { + M_printk("maestro: pm event received: 0x%x\n", rqst); + + switch (rqst) { + case PM_SUSPEND: + maestro_suspend(card); + break; + case PM_RESUME: + maestro_resume(card); + break; + } + } return 0; } -#endif diff -u --recursive --new-file v2.3.42/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.3.42/linux/drivers/sound/msnd_pinnacle.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sound/msnd_pinnacle.c Wed Feb 9 11:42:35 2000 @@ -1122,20 +1122,11 @@ } static struct file_operations dev_fileops = { - NULL, /* llseek */ - dev_read, /* read */ - dev_write, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - dev_ioctl, /* ioctl */ - NULL, /* mmap */ - dev_open, /* open */ -#ifndef LINUX20 - NULL, /* flush */ -#endif - dev_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ + read: dev_read, + write: dev_write, + ioctl: dev_ioctl, + open: dev_open, + release: dev_release, }; static int reset_dsp(void) diff -u --recursive --new-file v2.3.42/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c --- v2.3.42/linux/drivers/sound/nm256_audio.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sound/nm256_audio.c Tue Feb 8 18:49:27 2000 @@ -13,13 +13,10 @@ * off of it; go on, I dare you. */ -#include #define __NO_VERSION__ #include #include -#ifdef CONFIG_APM -#include -#endif +#include #include "sound_config.h" #include "soundmodule.h" #include "nm256.h" @@ -41,6 +38,7 @@ static int nm256_releaseInterrupt (struct nm256_info *card); static void nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy); static void nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy); +static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data); /* These belong in linux/pci.h. */ #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 @@ -1037,6 +1035,7 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr) { struct nm256_info *card; + struct pm_dev *pmdev; int x; card = kmalloc (sizeof (struct nm256_info), GFP_KERNEL); @@ -1211,50 +1210,42 @@ nm256_install_mixer (card); + pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pcidev), handle_pm_event); + if (pmdev) + pmdev->data = card; + return 1; } -#ifdef CONFIG_APM /* - * APM event handler, so the card is properly reinitialized after a power + * PM event handler, so the card is properly reinitialized after a power * event. */ static int -handle_apm_event (apm_event_t event) +handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data) { - static int down = 0; - - switch (event) - { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - down++; + struct nm256_info *crd = (struct nm256_info*) dev->data; + if (crd) { + switch (rqst) { + case PM_SUSPEND: break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - if (down) - { - struct nm256_info *crd; - - down = 0; - for (crd = nmcard_list; crd != NULL; crd = crd->next_card) - { - int playing = crd->playing; - nm256_full_reset (crd); - /* - * A little ugly, but that's ok; pretend the - * block we were playing is done. - */ - if (playing) - DMAbuf_outputintr (crd->dev_for_play, 1); - } - } + case PM_RESUME: + { + int playing = crd->playing; + nm256_full_reset (crd); + /* + * A little ugly, but that's ok; pretend the + * block we were playing is done. + */ + if (playing) + DMAbuf_outputintr (crd->dev_for_play, 1); + } break; } + } return 0; } -#endif /* * This loop walks the PCI configuration database and finds where @@ -1285,10 +1276,6 @@ if (count == 0) return -ENODEV; -#ifdef CONFIG_APM - apm_register_callback (&handle_apm_event); -#endif - printk (KERN_INFO "Done installing NM256 audio driver.\n"); return 0; } @@ -1699,9 +1686,7 @@ } nmcard_list = NULL; } -#ifdef CONFIG_APM - apm_unregister_callback (&handle_apm_event); -#endif + pm_unregister_all (&handle_pm_event); } #endif diff -u --recursive --new-file v2.3.42/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.3.42/linux/drivers/sound/sb_card.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sound/sb_card.c Wed Feb 9 18:48:03 2000 @@ -9,20 +9,25 @@ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * + * 26th November 1999 - patched to compile without ISA PnP support in the + * kernel. -Daniel Stone (tamriel@ductape.net) + * + * 06-01-2000 Refined and bugfixed ISA PnP support, added + * CMI 8330 support - Alessandro Zummo + * + * + * 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump + * Alessandro Zummo + * */ -/* 26th Novemner 1999 - patched to compile without ISA PnP support in the - kernel. -Daniel Stone (tamriel@ductape.net) */ - #include -#ifdef CONFIG_MCA #include -#endif #include #include -#ifdef CONFIG_ISAPNP /* Patched so it will compile withOUT ISA PnP */ #include -#endif #include "sound_config.h" #include "soundmodule.h" @@ -36,10 +41,8 @@ void attach_sb_card(struct address_info *hw_config) { -#if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) if(!sb_dsp_init(hw_config)) hw_config->slots[0] = -1; -#endif } int probe_sb(struct address_info *hw_config) @@ -91,7 +94,7 @@ hw_config->driver_use_2 = midiaddr[(pos2 >> 3) & 0x3]; */ - printk("SB: Reply MCA SB at slot=%d \ + printk(KERN_INFO "sb: Reply MCA SB at slot=%d \ iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n", slot+1, hw_config->io_base, hw_config->irq, @@ -99,12 +102,14 @@ } else { - printk ("Reply SB Base I/O address disabled\n"); + printk (KERN_INFO "sb: Reply SB Base I/O address disabled\n"); } } } #endif + /* This is useless since is done by sb_dsp_detect - azummo*/ + if (check_region(hw_config->io_base, 16)) { printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base); @@ -127,92 +132,403 @@ static struct address_info config; static struct address_info config_mpu; +struct pci_dev *sb_dev = NULL, + *wss_dev = NULL, + *jp_dev = NULL, + *mpu_dev = NULL, + *wt_dev = NULL; /* * Note DMA2 of -1 has the right meaning in the SB16 driver as well - * as here. It will cause either an error if it is needed or a fallback - * to the 8bit channel. + * as here. It will cause either an error if it is needed or a fallback + * to the 8bit channel. */ -int mpu_io = 0; -int io = -1; -int irq = -1; -int dma = -1; -int dma16 = -1; /* Set this for modules that need it */ -int type = 0; /* Can set this to a specific card type */ -int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ -int trix = 0; /* Set trix=1 to load this as support for trix */ -int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ -int support = 0; /* Set support to load this as a support module */ -int sm_games = 0; /* Mixer - see sb_mixer.c */ -int acer = 0; /* Do acer notebook init */ - -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(dma, "i"); -MODULE_PARM(dma16, "i"); -MODULE_PARM(mpu_io, "i"); -MODULE_PARM(type, "i"); -MODULE_PARM(mad16, "i"); -MODULE_PARM(support, "i"); -MODULE_PARM(trix, "i"); -MODULE_PARM(pas2, "i"); -MODULE_PARM(sm_games, "i"); -MODULE_PARM(esstype, "i"); +int mpu_io = 0; +int io = -1; +int irq = -1; +int dma = -1; +int dma16 = -1; /* Set this for modules that need it */ +int type = 0; /* Can set this to a specific card type */ +int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */ +int trix = 0; /* Set trix=1 to load this as support for trix */ +int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */ +int support = 0; /* Set support to load this as a support module */ +int sm_games = 0; /* Mixer - see sb_mixer.c */ +int acer = 0; /* Do acer notebook init */ + +#ifdef CONFIG_ISAPNP +int isapnp = 1; +int isapnpjump = 0; +#else +int isapnp = 0; +#endif + +MODULE_DESCRIPTION("Soundblaster driver"); + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(dma, "i"); +MODULE_PARM(dma16, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(type, "i"); +MODULE_PARM(mad16, "i"); +MODULE_PARM(support, "i"); +MODULE_PARM(trix, "i"); +MODULE_PARM(pas2, "i"); +MODULE_PARM(sm_games, "i"); +MODULE_PARM(esstype, "i"); +MODULE_PARM(acer, "i"); + +#ifdef CONFIG_ISAPNP +MODULE_PARM(isapnp, "i"); +MODULE_PARM(isapnpjump, "i"); +MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); +MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); +#endif + +MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); +MODULE_PARM_DESC(irq, "IRQ (5,7,9,10)"); +MODULE_PARM_DESC(dma, "8-bit DMA channel (0,1,3)"); +MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)"); +MODULE_PARM_DESC(mpu_io, "Mpu base address"); +MODULE_PARM_DESC(type, "You can set this to specific card type"); +MODULE_PARM_DESC(mad16, "Enable MAD16 support"); +MODULE_PARM_DESC(trix, "Enable Audiotrix support"); +MODULE_PARM_DESC(pas2, "Enable Pas2 support"); +MODULE_PARM_DESC(support, "Set this to load as generic support module"); +MODULE_PARM_DESC(sm_games, "Enable support for Logitech soundman games"); +MODULE_PARM_DESC(esstype, "ESS chip type"); +MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks"); void *smw_free = NULL; #ifdef CONFIG_ISAPNP -static struct { unsigned short vendor, function; char *name; } + +/* That's useful. */ + +static int check_base(char *devname, char *resname, struct resource *res) +{ + if (check_region(res->start, res->end - res->start)) + { + printk(KERN_ERR "sb: %s %s error, i/o at %#lx already in use\n", devname, resname, res->start); + return 0; + } + + printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, res->start); + return 1; +} + + +/* Card's specific initialization functions + */ + +static struct pci_dev *sb_init_generic(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +{ + if((sb_dev = isapnp_find_dev(card, + card->vendor, + card->device, + NULL))) + { + sb_dev->prepare(sb_dev); + sb_dev->activate(sb_dev); + + if (!sb_dev->resource[0].start) + return(NULL); + + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + mpu_config->io_base = sb_dev->resource[1].start; + } + return(sb_dev); +} + +static struct pci_dev *sb_init_ess(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +{ + if((sb_dev = isapnp_find_dev(card, + card->vendor, + card->device, + NULL))) + { + sb_dev->prepare(sb_dev); + sb_dev->activate(sb_dev); + + if (!sb_dev->resource[0].start) + return(NULL); + + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + mpu_config->io_base = sb_dev->resource[2].start; + } + return(sb_dev); +} + +static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +{ + /* What a stupid chip... where did they get all those @@@ ?*/ + + printk(KERN_INFO "sb: CMI8330 detected\n"); + + /* Soundblaster compatible logical device. */ + + if((sb_dev = isapnp_find_dev(card, + ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) + { +#ifdef CMI8330_DMA0BAD + int dmahack = 0; +#endif + sb_dev->prepare(sb_dev); + + /* This device doesn't work with DMA 0, so we must allocate + it to prevent PnP routines to assign it to the card. + + I know i could have inlined the following lines, but it's cleaner + this way. + */ + +#ifdef CMI8330_DMA0BAD + if(sb_dev->dma_resource[0].start == 0) + { + if(!request_dma(0, "cmi8330 dma hack")) + { + /* DMA was free, we now have it */ + dmahack = 1; + } + } +#endif + + if(sb_dev->activate(sb_dev) >= 0) + { + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + + check_base("CMI8330", "sb", &sb_dev->resource[0]); + } + else + printk(KERN_ERR "sb: CMI8330 sb config failed (out of resources?)\n"); + +#ifdef CMI8330_DMA0BAD + if(dmahack) + free_dma(0); +#endif + } + else + printk(KERN_ERR "sb: CMI8330 panic! sb base not found\n"); + + if((mpu_dev = isapnp_find_dev(card, + ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) + { + mpu_dev->prepare(mpu_dev); + + /* This disables the interrupt on this resource. Do we need it ? */ + + mpu_dev->irq_resource[0].flags = 0; + + if(mpu_dev->activate(mpu_dev) >= 0) + { + if( check_base("CMI8330", "mpu", &mpu_dev->resource[0]) ) + mpu_config->io_base = mpu_dev->resource[0].start; + } + else + printk(KERN_ERR "sb: CMI8330 mpu config failed (out of resources?)\n"); + } + else + printk(KERN_ERR "sb: CMI8330 panic! mpu not found\n"); + + + /* Gameport. */ + + if((jp_dev = isapnp_find_dev(card, + ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) + { + jp_dev->prepare(jp_dev); + + if(jp_dev->activate(jp_dev) >= 0) + { + check_base("CMI8330", "gameport", &jp_dev->resource[0]); + } + else + printk(KERN_ERR "sb: CMI8330 gameport config failed (out of resources?)\n"); + } + else + printk(KERN_ERR "sb: CMI8330 panic! gameport not found\n"); + + + /* OPL3 support */ + +#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE) + if((wss_dev = isapnp_find_dev(card, + ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) + { + wss_dev->prepare(wss_dev); + + /* Let's disable IRQ and DMA for WSS device */ + + wss_dev->irq_resource[0].flags = 0; + wss_dev->dma_resource[0].flags = 0; + + if(wss_dev->activate(wss_dev) >= 0) + { + check_base("CMI8330", "opl3", &wss_dev->resource[1]); + } + else + printk(KERN_ERR "sb: CMI8330 opl3 config failed (out of resources?)\n"); + } + else + printk(KERN_ERR "sb: CMI8330 panic! opl3 not found\n"); +#endif + + printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo \n"); + + return(sb_dev); +} + +static struct pci_dev *sb_init_awe64(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +{ + printk(KERN_INFO "sb: SoundBlaster AWE 64 detected\n"); + + /* CTL0042:Audio. */ + + if((sb_dev = isapnp_find_dev(card, + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL))) + { + sb_dev->prepare(sb_dev); + + if(sb_dev->activate(sb_dev) >= 0) + { + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + + mpu_config->io_base = sb_dev->resource[1].start; + + check_base("AWE64", "sb", &sb_dev->resource[0]); + check_base("AWE64", "mpu", &sb_dev->resource[1]); + check_base("AWE64", "opl3", &sb_dev->resource[2]); + } + else + printk(KERN_ERR "sb: AWE64 sb config failed (out of resources?)\n"); + } + else + printk(KERN_ERR "sb: AWE64 panic! sb base not found\n"); + + + /* CTL7002:Game */ + + if((jp_dev = isapnp_find_dev(card, + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL))) + { + jp_dev->prepare(jp_dev); + + if(jp_dev->activate(jp_dev) >= 0) + { + check_base("AWE64", "gameport", &jp_dev->resource[0]); + } + else + printk(KERN_ERR "sb: AWE64 gameport config failed (out of resources?)\n"); + } + else + printk(KERN_ERR "sb: AWE64 panic! gameport not found\n"); + + + /* CTL0022:WaveTable */ + + if((wt_dev = isapnp_find_dev(card, + ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL))) + { + wt_dev->prepare(wt_dev); + + if(wt_dev->activate(wt_dev) >= 0) + { + check_base("AWE64", "wavetable", &wt_dev->resource[0]); + check_base("AWE64", "wavetable", &wt_dev->resource[1]); + check_base("AWE64", "wavetable", &wt_dev->resource[2]); + } + else + printk(KERN_ERR "sb: AWE64 wavetable config failed (out of resources?)\n"); + } + else + printk(KERN_ERR "sb: AWE64 panic! wavetable not found\n"); + + printk(KERN_INFO "sb: AWE64 mail reports to Alessandro Zummo \n"); + + return(sb_dev); +} + + +static struct { unsigned short vendor, function; struct pci_dev * (*initfunc)(struct pci_bus *, struct address_info *, struct address_info *); char *name; } isapnp_sb_list[] __initdata = { - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), "Sound Blaster 16" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), "ESS 1869" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), "ESS 1878" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), "ESS 1879" }, - {0,} + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), &sb_init_awe64, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), &sb_init_ess, "ESS 1869" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), &sb_init_ess, "ESS 1878" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), &sb_init_ess, "ESS 1879" }, + {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), &sb_init_cmi, "CMI 8330 SoundPRO" }, + {0} }; +/* Actually this routine will detect and configure only the first card with successful + initalization. isapnpjump could be used to jump to a specific entry. + Please always add entries at the end of the array. + Should this be fixed? - azummo +*/ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) { + int i; + + /* Count entries in isapnp_sb_list */ + for (i = 0; isapnp_sb_list[i].vendor != 0; i++); + + /* Check and adjust isapnpjump */ + if( isapnpjump < 0 || isapnpjump > ( i - 1 ) ) + { + printk(KERN_ERR "sb: Valid range for isapnpjump is 0-%d. Adjusted to 0.\n", i-1); + isapnpjump = 0; + } - for (i = 0; isapnp_sb_list[i].vendor != 0; i++) { - struct pci_dev *idev = NULL; + for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) { + struct pci_bus *card = NULL; - while ((idev = isapnp_find_dev(NULL, + while ((card = isapnp_find_card( isapnp_sb_list[i].vendor, isapnp_sb_list[i].function, - idev))) { - idev->prepare(idev); - idev->activate(idev); - if (!idev->resource[0].start || check_region(idev->resource[0].start,16)) - continue; - hw_config->io_base = idev->resource[0].start; - hw_config->irq = idev->irq_resource[0].start; - hw_config->dma = idev->dma_resource[0].start; - hw_config->dma2 = idev->dma_resource[1].start; -#ifdef CONFIG_MIDI - if (isapnp_sb_list[i].vendor == ISAPNP_VENDOR('E','S','S')) - mpu_config->io_base = idev->resource[2].start; - else - mpu_config->io_base = idev->resource[1].start; -#endif - break; + card))) { + + /* You missed the init func? That's bad. */ + + if(isapnp_sb_list[i].initfunc) + { + struct pci_dev *idev = NULL; + + /* Initialize this baby. */ + + if((idev = isapnp_sb_list[i].initfunc(card, hw_config, mpu_config))) + { + /* We got it. */ + + printk(KERN_INFO "sb: ISAPnP reports %s at i/o %#x, irq %d, dma %d, %d\n", + isapnp_sb_list[i].name, + hw_config->io_base, hw_config->irq, hw_config->dma, + hw_config->dma2); + return 0; + } + } } - if (!idev) - continue; - printk(KERN_INFO "ISAPnP reports %s at i/o %#x, irq %d, dma %d, %d\n", - isapnp_sb_list[i].name, - hw_config->io_base, hw_config->irq, hw_config->dma, - hw_config->dma2); - return 0; } return -ENODEV; } @@ -224,38 +540,52 @@ if (mad16 == 0 && trix == 0 && pas2 == 0 && support == 0) { + /* Please remember that even with CONFIG_ISAPNP defined one should still be + able to disable PNP support for this single driver! + */ + #ifdef CONFIG_ISAPNP - if (sb_probe_isapnp(&config, &config_mpu)<0) + if (isapnp) + { + if(sb_probe_isapnp(&config, &config_mpu) < 0 ) + { + printk(KERN_ERR "sb_card: No ISAPnP cards found\n"); + return -EINVAL; + } + } + else { -#endif +#endif if (io == -1 || dma == -1 || irq == -1) { printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n"); return -EINVAL; } - config.io_base = io; - config.irq = irq; - config.dma = dma; - config.dma2 = dma16; - config.card_subtype = type; -#ifdef CONFIG_MIDI - config_mpu.io_base = mpu_io; -#endif + + config.io_base = io; + config.irq = irq; + config.dma = dma; + config.dma2 = dma16; #ifdef CONFIG_ISAPNP } #endif + + /* If this is not before the #ifdef line, there's a reason... */ + config.card_subtype = type; + if (!probe_sb(&config)) return -ENODEV; attach_sb_card(&config); if(config.slots[0]==-1) return -ENODEV; -#ifdef CONFIG_MIDI + + if (isapnp == 0) + config_mpu.io_base = mpu_io; if (probe_sbmpu(&config_mpu)) sbmpu = 1; if (sbmpu) attach_sbmpu(&config_mpu); -#endif } SOUND_LOCK; return 0; @@ -270,6 +600,12 @@ if (sbmpu) unload_sbmpu(&config_mpu); SOUND_LOCK_END; + + if(sb_dev) sb_dev->deactivate(sb_dev); + if(jp_dev) jp_dev->deactivate(jp_dev); + if(wt_dev) wt_dev->deactivate(wt_dev); + if(mpu_dev) mpu_dev->deactivate(mpu_dev); + if(wss_dev) wss_dev->deactivate(wss_dev); } #else diff -u --recursive --new-file v2.3.42/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.3.42/linux/drivers/sound/sonicvibes.c Fri Jan 21 18:19:17 2000 +++ linux/drivers/sound/sonicvibes.c Wed Feb 9 11:42:35 2000 @@ -87,6 +87,7 @@ * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun; * Tim Janik's BSE (Bedevilled Sound Engine) found this * use Martin Mares' pci_assign_resource + * 07.02.2000 0.26 Use pci_alloc_consistent and pci_register_driver * */ @@ -287,8 +288,11 @@ /* magic */ unsigned int magic; - /* we keep sv cards in a linked list */ - struct sv_state *next; + /* list of sonicvibes devices */ + struct list_head devs; + + /* the corresponding pci_dev structure */ + struct pci_dev *dev; /* soundcore stuff */ int dev_audio; @@ -319,6 +323,7 @@ struct dmabuf { void *rawbuf; + dma_addr_t dmaaddr; unsigned buforder; unsigned numfrag; unsigned fragshift; @@ -354,7 +359,7 @@ /* --------------------------------------------------------------------- */ -static struct sv_state *devs = NULL; +static LIST_HEAD(devs); static unsigned long wavetable_mem = 0; /* --------------------------------------------------------------------- */ @@ -684,7 +689,7 @@ #define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 -static void dealloc_dmabuf(struct dmabuf *db) +static void dealloc_dmabuf(struct sv_state *s, struct dmabuf *db) { unsigned long map, mapend; @@ -693,7 +698,7 @@ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (map = MAP_NR(db->rawbuf); map <= mapend; map++) clear_bit(PG_reserved, &mem_map[map].flags); - free_pages((unsigned long)db->rawbuf, db->buforder); + pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); } db->rawbuf = NULL; db->mapped = db->ready = 0; @@ -729,7 +734,7 @@ if (!db->rawbuf) { db->ready = db->mapped = 0; for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order))) + if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) break; if (!db->rawbuf) return -ENOMEM; @@ -770,12 +775,12 @@ memset(db->rawbuf, (fmt & SV_CFMT_16BIT) ? 0 : 0x80, db->dmasize); spin_lock_irqsave(&s->lock, flags); if (rec) { - set_dmac(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + set_dmac(s, db->dmaaddr, db->numfrag << db->fragshift); /* program enhanced mode registers */ wrindir(s, SV_CIDMACBASECOUNT1, (db->fragsamples-1) >> 8); wrindir(s, SV_CIDMACBASECOUNT0, db->fragsamples-1); } else { - set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); + set_dmaa(s, db->dmaaddr, db->numfrag << db->fragshift); /* program enhanced mode registers */ wrindir(s, SV_CIDMAABASECOUNT1, (db->fragsamples-1) >> 8); wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1); @@ -1223,12 +1228,16 @@ static int sv_open_mixdev(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); - struct sv_state *s = devs; + struct list_head *list; + struct sv_state *s; - while (s && s->dev_mixer != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct sv_state, devs); + if (s->dev_mixer == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; MOD_INC_USE_COUNT; @@ -1250,19 +1259,10 @@ } static /*const*/ struct file_operations sv_mixer_fops = { - &sv_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &sv_ioctl_mixdev, - NULL, /* mmap */ - &sv_open_mixdev, - NULL, /* flush */ - &sv_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: sv_llseek, + ioctl: sv_ioctl_mixdev, + open: sv_open_mixdev, + release: sv_release_mixdev, }; /* --------------------------------------------------------------------- */ @@ -1852,13 +1852,17 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct sv_state *s = devs; unsigned char fmtm = ~0, fmts = 0; + struct list_head *list; + struct sv_state *s; - while (s && ((s->dev_audio ^ minor) & ~0xf)) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct sv_state, devs); + if (!((s->dev_audio ^ minor) & ~0xf)) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -1909,11 +1913,11 @@ down(&s->open_sem); if (file->f_mode & FMODE_WRITE) { stop_dac(s); - dealloc_dmabuf(&s->dma_dac); + dealloc_dmabuf(s, &s->dma_dac); } if (file->f_mode & FMODE_READ) { stop_adc(s); - dealloc_dmabuf(&s->dma_adc); + dealloc_dmabuf(s, &s->dma_adc); } s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); wake_up(&s->open_wait); @@ -1923,19 +1927,14 @@ } static /*const*/ struct file_operations sv_audio_fops = { - &sv_llseek, - &sv_read, - &sv_write, - NULL, /* readdir */ - &sv_poll, - &sv_ioctl, - &sv_mmap, - &sv_open, - NULL, /* flush */ - &sv_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: sv_llseek, + read: sv_read, + write: sv_write, + poll: sv_poll, + ioctl: sv_ioctl, + mmap: sv_mmap, + open: sv_open, + release: sv_release, }; /* --------------------------------------------------------------------- */ @@ -2098,13 +2097,17 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct sv_state *s = devs; unsigned long flags; + struct list_head *list; + struct sv_state *s; - while (s && s->dev_midi != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct sv_state, devs); + if (s->dev_midi == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -2203,19 +2206,12 @@ } static /*const*/ struct file_operations sv_midi_fops = { - &sv_llseek, - &sv_midi_read, - &sv_midi_write, - NULL, /* readdir */ - &sv_midi_poll, - NULL, /* ioctl */ - NULL, /* mmap */ - &sv_midi_open, - NULL, /* flush */ - &sv_midi_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: sv_llseek, + read: sv_midi_read, + write: sv_midi_write, + poll: sv_midi_poll, + open: sv_midi_open, + release: sv_midi_release, }; /* --------------------------------------------------------------------- */ @@ -2321,12 +2317,16 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - struct sv_state *s = devs; + struct list_head *list; + struct sv_state *s; - while (s && s->dev_dmfm != minor) - s = s->next; - if (!s) - return -ENODEV; + for (list = devs.next; ; list = list->next) { + if (list == &devs) + return -ENODEV; + s = list_entry(list, struct sv_state, devs); + if (s->dev_dmfm == minor) + break; + } VALIDATE_STATE(s); file->private_data = s; /* wait for device to become free */ @@ -2380,24 +2380,15 @@ } static /*const*/ struct file_operations sv_dmfm_fops = { - &sv_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &sv_dmfm_ioctl, - NULL, /* mmap */ - &sv_dmfm_open, - NULL, /* flush */ - &sv_dmfm_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: sv_llseek, + ioctl: sv_dmfm_ioctl, + open: sv_dmfm_open, + release: sv_dmfm_release, }; /* --------------------------------------------------------------------- */ -/* maximum number of devices */ +/* maximum number of devices; only used for command line params */ #define NR_DEVICE 5 static int reverb[NR_DEVICE] = { 0, }; @@ -2406,6 +2397,8 @@ static int wavetable[NR_DEVICE] = { 0, }; #endif +static unsigned int devindex = 0; + MODULE_PARM(reverb, "1-" __MODULE_STRING(NR_DEVICE) "i"); MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM"); #if 0 @@ -2437,216 +2430,235 @@ ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) -static int __init init_sonicvibes(void) +static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { static const char __initlocaldata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller"; struct sv_state *s; - struct pci_dev *pcidev = NULL; mm_segment_t fs; - int i, val, index = 0; + int i, val; char *ddmaname; unsigned ddmanamelen; + if (!RSRCISIOREGION(pcidev, RESOURCE_SB) || + !RSRCISIOREGION(pcidev, RESOURCE_ENH) || + !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) || + !RSRCISIOREGION(pcidev, RESOURCE_MIDI) || + !RSRCISIOREGION(pcidev, RESOURCE_GAME)) + return -1; + if (pcidev->irq == 0) + return -1; + /* try to allocate a DDMA resource if not already available */ + if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) { + pcidev->resource[RESOURCE_DDMA].start = 0; + pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1; + pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO; + ddmanamelen = strlen(sv_ddma_name)+1; + if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL))) + return -1; + memcpy(ddmaname, sv_ddma_name, ddmanamelen); + pcidev->resource[RESOURCE_DDMA].name = ddmaname; + if (pci_assign_resource(pcidev, RESOURCE_DDMA)) { + pcidev->resource[RESOURCE_DDMA].name = NULL; + kfree(ddmaname); + printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n"); + return -1; + } + } + if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) { + printk(KERN_WARNING "sv: out of memory\n"); + return -1; + } + memset(s, 0, sizeof(struct sv_state)); + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->midi.iwait); + init_waitqueue_head(&s->midi.owait); + init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); + s->magic = SV_MAGIC; + s->dev = pcidev; + s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB); + s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH); + s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH); + s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI); + s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME); + s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA); + s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA; + pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ + pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ + printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", + s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac); + s->irq = pcidev->irq; + + /* hack */ + pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */ + + if (!request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM")) { + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); + goto err_region5; + } + if (!request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA")) { + printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1); + goto err_region4; + } + if (!request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC")) { + printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1); + goto err_region3; + } + if (!request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi")) { + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); + goto err_region2; + } + if (!request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth")) { + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); + goto err_region1; + } + pci_enable_device(pcidev); + /* initialize codec registers */ + outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */ + udelay(50); + outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */ + udelay(50); + outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */ + | (reverb[devindex] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL); + inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */ + wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */ + wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */ + outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK); + /* outb(0xff, s->iodmaa + SV_DMA_RESET); */ + /* outb(0xff, s->iodmac + SV_DMA_RESET); */ + inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ + wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */ + wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */ + wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */ + setpll(s, SV_CIADCPLLM, 8000); + wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */ + wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff); + wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff); + wrindir(s, SV_CIADCOUTPUT, 0); + /* request irq */ + if (request_irq(s->irq, sv_interrupt, SA_SHIRQ, "S3 SonicVibes", s)) { + printk(KERN_ERR "sv: irq %u in use\n", s->irq); + goto err_irq; + } + printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n", + s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION)); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) + goto err_dev1; + if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0) + goto err_dev2; + if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0) + goto err_dev3; + if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0) + goto err_dev4; + pci_set_master(pcidev); /* enable bus mastering */ + /* initialize the chips */ + fs = get_fs(); + set_fs(KERNEL_DS); + val = SOUND_MASK_LINE|SOUND_MASK_SYNTH; + mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); + for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { + val = initvol[i].vol; + mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); + } + set_fs(fs); + /* store it in the driver field */ + pcidev->driver_data = s; + pcidev->dma_mask = 0x00ffffff; + /* put it into driver list */ + list_add_tail(&s->devs, &devs); + /* increment devindex */ + if (devindex < NR_DEVICE-1) + devindex++; + return 0; + + err_dev4: + unregister_sound_midi(s->dev_midi); + err_dev3: + unregister_sound_mixer(s->dev_mixer); + err_dev2: + unregister_sound_dsp(s->dev_audio); + err_dev1: + printk(KERN_ERR "sv: cannot register misc device\n"); + free_irq(s->irq, s); + err_irq: + release_region(s->iosynth, SV_EXTENT_SYNTH); + err_region1: + release_region(s->iomidi, SV_EXTENT_MIDI); + err_region2: + release_region(s->iodmac, SV_EXTENT_DMA); + err_region3: + release_region(s->iodmaa, SV_EXTENT_DMA); + err_region4: + release_region(s->ioenh, SV_EXTENT_ENH); + err_region5: + kfree_s(s, sizeof(struct sv_state)); + return -1; +} + +static void sv_remove(struct pci_dev *dev) +{ + struct sv_state *s = (struct sv_state *)dev->driver_data; + + if (!s) + return; + list_del(&s->devs); + outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ + synchronize_irq(); + inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ + wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ + /*outb(0, s->iodmaa + SV_DMA_RESET);*/ + /*outb(0, s->iodmac + SV_DMA_RESET);*/ + free_irq(s->irq, s); + release_region(s->iodmac, SV_EXTENT_DMA); + release_region(s->iodmaa, SV_EXTENT_DMA); + release_region(s->ioenh, SV_EXTENT_ENH); + release_region(s->iomidi, SV_EXTENT_MIDI); + release_region(s->iosynth, SV_EXTENT_SYNTH); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->dev_mixer); + unregister_sound_midi(s->dev_midi); + unregister_sound_special(s->dev_dmfm); + kfree_s(s, sizeof(struct sv_state)); + dev->driver_data = NULL; +} + +static const struct pci_device_id id_table[] = { + { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } +}; + +MODULE_DEVICE_TABLE(pci, id_table); + +static struct pci_driver sv_driver = { + name: "sonicvibes", + id_table: id_table, + probe: sv_probe, + remove: sv_remove +}; + +static int __init init_sonicvibes(void) +{ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.25 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.26 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); #endif - while (index < NR_DEVICE && - (pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, pcidev))) { - if (!RSRCISIOREGION(pcidev, RESOURCE_SB) || - !RSRCISIOREGION(pcidev, RESOURCE_ENH) || - !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) || - !RSRCISIOREGION(pcidev, RESOURCE_MIDI) || - !RSRCISIOREGION(pcidev, RESOURCE_GAME)) - continue; - if (pcidev->irq == 0) - continue; - /* try to allocate a DDMA resource if not already available */ - if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) { - pcidev->resource[RESOURCE_DDMA].start = 0; - pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1; - pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO; - ddmanamelen = strlen(sv_ddma_name)+1; - if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL))) - continue; - memcpy(ddmaname, sv_ddma_name, ddmanamelen); - pcidev->resource[RESOURCE_DDMA].name = ddmaname; - if (pci_assign_resource(pcidev, RESOURCE_DDMA)) { - pcidev->resource[RESOURCE_DDMA].name = NULL; - kfree(ddmaname); - printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n"); - continue; - } - } - if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) { - printk(KERN_WARNING "sv: out of memory\n"); - continue; - } - memset(s, 0, sizeof(struct sv_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - init_MUTEX(&s->open_sem); - spin_lock_init(&s->lock); - s->magic = SV_MAGIC; - s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB); - s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH); - s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH); - s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI); - s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME); - s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA); - s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA; - pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ - pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ - printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", - s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac); - s->irq = pcidev->irq; - - /* hack */ - pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */ - - if (check_region(s->ioenh, SV_EXTENT_ENH)) { - printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); - goto err_region5; - } - request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM"); - if (check_region(s->iodmaa, SV_EXTENT_DMA)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1); - goto err_region4; - } - request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA"); - if (check_region(s->iodmac, SV_EXTENT_DMA)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1); - goto err_region3; - } - request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC"); - if (check_region(s->iomidi, SV_EXTENT_MIDI)) { - printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); - goto err_region2; - } - request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi"); - if (check_region(s->iosynth, SV_EXTENT_SYNTH)) { - printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); - goto err_region1; - } - request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth"); - /* initialize codec registers */ - outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */ - udelay(50); - outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */ - udelay(50); - outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */ - | (reverb[index] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL); - inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */ - wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */ - wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */ - outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK); - /* outb(0xff, s->iodmaa + SV_DMA_RESET); */ - /* outb(0xff, s->iodmac + SV_DMA_RESET); */ - inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ - wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */ - wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */ - wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */ - setpll(s, SV_CIADCPLLM, 8000); - wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */ - wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff); - wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff); - wrindir(s, SV_CIADCOUTPUT, 0); - /* request irq */ - if (request_irq(s->irq, sv_interrupt, SA_SHIRQ, "S3 SonicVibes", s)) { - printk(KERN_ERR "sv: irq %u in use\n", s->irq); - goto err_irq; - } - printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n", - s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION)); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0) - goto err_dev2; - if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0) - goto err_dev3; - if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0) - goto err_dev4; - pci_set_master(pcidev); /* enable bus mastering */ - /* initialize the chips */ - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE|SOUND_MASK_SYNTH; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); - } - set_fs(fs); - /* queue it for later freeing */ - s->next = devs; - devs = s; - index++; - continue; - - err_dev4: - unregister_sound_midi(s->dev_midi); - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR "sv: cannot register misc device\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->iosynth, SV_EXTENT_SYNTH); - err_region1: - release_region(s->iomidi, SV_EXTENT_MIDI); - err_region2: - release_region(s->iodmac, SV_EXTENT_DMA); - err_region3: - release_region(s->iodmaa, SV_EXTENT_DMA); - err_region4: - release_region(s->ioenh, SV_EXTENT_ENH); - err_region5: - kfree_s(s, sizeof(struct sv_state)); - } - if (!devs) { - if (wavetable_mem) - free_pages(wavetable_mem, 20-PAGE_SHIFT); - return -ENODEV; - } - return 0; + if (!pci_register_driver(&sv_driver)) + return -ENODEV; + return 0; } static void __exit cleanup_sonicvibes(void) { - struct sv_state *s; - - while ((s = devs)) { - devs = devs->next; - outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */ - synchronize_irq(); - inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */ - wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */ - /*outb(0, s->iodmaa + SV_DMA_RESET);*/ - /*outb(0, s->iodmac + SV_DMA_RESET);*/ - free_irq(s->irq, s); - release_region(s->iodmac, SV_EXTENT_DMA); - release_region(s->iodmaa, SV_EXTENT_DMA); - release_region(s->ioenh, SV_EXTENT_ENH); - release_region(s->iomidi, SV_EXTENT_MIDI); - release_region(s->iosynth, SV_EXTENT_SYNTH); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->dev_mixer); - unregister_sound_midi(s->dev_midi); - unregister_sound_special(s->dev_dmfm); - kfree_s(s, sizeof(struct sv_state)); - } - if (wavetable_mem) - free_pages(wavetable_mem, 20-PAGE_SHIFT); printk(KERN_INFO "sv: unloading\n"); + pci_unregister_driver(&sv_driver); + if (wavetable_mem) + free_pages(wavetable_mem, 20-PAGE_SHIFT); } module_init(init_sonicvibes); diff -u --recursive --new-file v2.3.42/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.3.42/linux/drivers/sound/soundcard.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/sound/soundcard.c Thu Feb 10 12:32:03 2000 @@ -778,16 +778,14 @@ struct file_operations oss_sound_fops = { - sound_lseek, - sound_read, - sound_write, - NULL, /* sound_readdir */ - sound_poll, - sound_ioctl, - sound_mmap, - sound_open, - NULL, /* flush */ - sound_release + llseek: sound_lseek, + read: sound_read, + write: sound_write, + poll: sound_poll, + ioctl: sound_ioctl, + mmap: sound_mmap, + open: sound_open, + release: sound_release, }; /* @@ -877,8 +875,10 @@ int init_module(void) { int err; +#if FIXED_FOR_2_4_0 int ints[21]; int i; +#endif trace_init=traceinit; @@ -890,6 +890,7 @@ printk(KERN_ERR "sound: rebuild with PCI_QUIRKS enabled to configure this.\n"); #endif +#if FIXED_FOR_2_4_0 /* * "sound=" command line handling by Harald Milz. */ @@ -900,6 +901,7 @@ if (i) sound_setup("sound=", ints); +#endif err = create_special_devices(); if (err) diff -u --recursive --new-file v2.3.42/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.3.42/linux/drivers/sound/trident.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/sound/trident.c Wed Feb 9 18:48:03 2000 @@ -29,6 +29,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.11.1 Jan 28 2000 Ollie Lho + * small bug in setting sample rate for 4d-nx (reported by Aaron) * v0.11 Jan 27 2000 Ollie Lho * DMA bug, scheduler latency, second try * v0.10 Jan 24 2000 Ollie Lho @@ -61,7 +63,6 @@ * "Channel Binding" ioctl extension */ -#include #include #include #include @@ -81,16 +82,12 @@ #include #include -#ifdef CONFIG_APM -#include -#endif - #include "trident.h" #include "ac97_codec.h" #undef DEBUG -#define DRIVER_VERSION "0.11" +#define DRIVER_VERSION "0.11.1" /* magic numbers to protect our data structures */ #define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */ @@ -527,7 +524,7 @@ break; case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX: data[0] = (channel->delta << 24); - data[2] = ((channel->delta << 24) & 0xff000000) | (channel->eso & 0x00ffffff); + data[2] = ((channel->delta << 16) & 0xff000000) | (channel->eso & 0x00ffffff); data[3] = channel->fm_vol & 0xffff; break; default: @@ -1837,19 +1834,14 @@ } static /*const*/ struct file_operations trident_audio_fops = { - &trident_llseek, - &trident_read, - &trident_write, - NULL, /* readdir */ - &trident_poll, - &trident_ioctl, - &trident_mmap, - &trident_open, - NULL, /* flush */ - &trident_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: trident_llseek, + read: trident_read, + write: trident_write, + poll: trident_poll, + ioctl: trident_ioctl, + mmap: trident_mmap, + open: trident_open, + release: trident_release, }; /* trident specific AC97 functions */ @@ -1999,19 +1991,10 @@ } static /*const*/ struct file_operations trident_mixer_fops = { - &trident_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &trident_ioctl_mixdev, - NULL, /* mmap */ - &trident_open_mixdev, - NULL, /* flush */ - &trident_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: trident_llseek, + ioctl: trident_ioctl_mixdev, + open: trident_open_mixdev, + release: trident_release_mixdev, }; /* AC97 codec initialisation. */ diff -u --recursive --new-file v2.3.42/linux/drivers/sound/via82cxxx.c linux/drivers/sound/via82cxxx.c --- v2.3.42/linux/drivers/sound/via82cxxx.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sound/via82cxxx.c Wed Dec 31 16:00:00 1969 @@ -1,721 +0,0 @@ -/* - * Support for VIA 82Cxxx Audio Codecs - * Copyright 1999,2000 Jeff Garzik - * - * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2. - * See the "COPYING" file distributed with this software for more info. - * - * Documentation for this driver available as - * linux/Documentation/sound/via82cxxx.txt. - * - * Since the mixer is called from the OSS glue the kernel lock is always held - * on our AC97 mixing - */ - - -#define VIA_VERSION "1.1.2" - - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sound_config.h" -#include "soundmodule.h" -#include "sb.h" -#include "ac97.h" - -#ifndef SOUND_LOCK -#define SOUND_LOCK do {} while (0) -#define SOUND_LOCK_END do {} while (0) -#endif - -#define VIA_DEBUG 0 /* define to 1 to enable debugging output and checks */ -#if VIA_DEBUG -/* note: prints function name for you */ -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) -#else -#define DPRINTK(fmt, args...) -#endif - -#define VIA_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ -#if VIA_NDEBUG -#define assert(expr) -#else -#define assert(expr) \ - if(!(expr)) { \ - printk( "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ - } -#endif - -#define arraysize(x) (sizeof(x)/sizeof(*(x))) - -#define MAX_CARDS 2 - -#define LINE_SIZE 10 - -#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION -#define VIA_MODULE_NAME "via82cxxx" -#define PFX VIA_MODULE_NAME ": " - -#define VIA_COUNTER_LIMIT 100000 - -/* 82C686 function 5 (audio codec) PCI configuration registers */ -#define VIA_FUNC_ENABLE 0x42 -#define VIA_PNP_CONTROL 0x43 -#define VIA_AC97_CTRL 0x80 - -/* PCI configuration register bits and masks */ -#define VIA_CR40_AC97_READY 0x01 -#define VIA_CR40_AC97_LOW_POWER 0x02 -#define VIA_CR40_SECONDARY_READY 0x04 - -#define VIA_CR41_ACLINK_ENABLE 0x80 - -#define VIA_CR42_SB_ENABLE 0x01 -#define VIA_CR42_MIDI_ENABLE 0x02 -#define VIA_CR42_FM_ENABLE 0x04 -#define VIA_CR42_GAME_ENABLE 0x08 - -#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6) -#define VIA_CR44_AC_LINK_ACCESS (1 << 7) - -#define VIA_CR80_FIRST_CODEC 0 -#define VIA_CR80_SECOND_CODEC (1 << 30) -#define VIA_CR80_FIRST_CODEC_VALID (1 << 25) -#define VIA_CR80_SECOND_CODEC_VALID (1 << 27) -#define VIA_CR80_BUSY (1 << 24) -#define VIA_CR80_READ_MODE (1 << 23) -#define VIA_CR80_WRITE_MODE 0 -#define VIA_CR80_REG_IDX(idx) (((idx) & 0x7E) << 16) - -struct via_info { - struct address_info sb_data; - struct address_info opl3_data; - struct pci_dev *pdev; - struct ac97_hwint ac97; - int mixer_oss_dev; - int have_ac97; -}; -static struct via_info cards [MAX_CARDS]; -static unsigned num_cards = 0; - - -static const struct { - int revision; - const char *rev_name; -} via_chip_revs[] __initdata = { - { 0x10, "A" }, - { 0x11, "B" }, - { 0x12, "C" }, - { 0x13, "D" }, - { 0x14, "E" }, - { 0x20, "H" }, -}; - -static inline void via_ac97_write32 (struct pci_dev *pdev, int port, u32 data) -{ - struct resource *rsrc = &pdev->resource[0]; - outw ((u16)data,rsrc->start+port); - outw ((u16)(data>>16),rsrc->start+port+2); -} - -static inline u32 via_ac97_read32 (struct pci_dev *pdev, int port) -{ - struct resource *rsrc = &pdev->resource[0]; - return - ((u32)inw (rsrc->start+port)) | - (((u32)inw (rsrc->start+port+2)) << 16); -} - -/**************************************************************** - * - * Intel Audio Codec '97 interface - * - * - */ - -static inline void via_ac97_wait_idle (struct pci_dev *pdev) -{ - u32 tmp; - int counter = VIA_COUNTER_LIMIT; - - DPRINTK ("ENTER\n"); - - assert (pdev != NULL); - - do { - tmp = via_ac97_read32 (pdev,VIA_AC97_CTRL); - } while ((tmp & VIA_CR80_BUSY) && (counter-- > 0)); - - DPRINTK ("EXIT%s\n", counter > 0 ? "" : ", counter limit reached"); -} - - -static int via_ac97_read_reg (struct ac97_hwint *dev, u8 reg) -{ - u32 data; - struct via_info *card; - struct pci_dev *pdev; - - DPRINTK ("ENTER\n"); - - assert (dev != NULL); - assert (dev->driver_private != NULL); - - card = (struct via_info *) dev->driver_private; - pdev = card->pdev; - assert (pdev != NULL); - - via_ac97_wait_idle (pdev); - data = VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID | - VIA_CR80_READ_MODE | VIA_CR80_REG_IDX(reg); - via_ac97_write32 (pdev,VIA_AC97_CTRL,data); - via_ac97_wait_idle (pdev); - data = via_ac97_read32 (pdev,VIA_AC97_CTRL); - -#if 0 - if (! (data & VIA_CR80_FIRST_CODEC_VALID)) { - DPRINTK ("EXIT, first codec not valid, returning -1\n"); - return -1; - } -#endif - - DPRINTK ("EXIT, returning %d\n", data & 0xFFFF); - return data & 0xFFFF; -} - - -static int via_ac97_write_reg (struct ac97_hwint *dev, u8 reg, u16 value) -{ - u32 data; - struct via_info *card; - struct pci_dev *pdev; - - DPRINTK ("ENTER\n"); - - assert (dev != NULL); - assert (dev->driver_private != NULL); - - card = (struct via_info *) dev->driver_private; - pdev = card->pdev; - assert (pdev != NULL); - - via_ac97_wait_idle (pdev); - data = VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID | - VIA_CR80_WRITE_MODE | VIA_CR80_REG_IDX(reg) | value; - via_ac97_write32 (pdev,VIA_AC97_CTRL,data); - -#if 0 - if (! (data & VIA_CR80_FIRST_CODEC_VALID)) { - DPRINTK ("EXIT, first codec invalid, returning -1\n"); - return -1; - } -#endif - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -static int via_ac97_reset (struct ac97_hwint *dev) -{ - struct via_info *card; - struct pci_dev *pdev; - - DPRINTK ("ENTER\n"); - - assert (dev != NULL); - assert (dev->driver_private != NULL); - - card = (struct via_info *) dev->driver_private; - pdev = card->pdev; - assert (pdev != NULL); - - pci_write_config_word (pdev, PCI_COMMAND, PCI_COMMAND_IO); - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -static struct via_info *via_ac97_find_card_for_mixer (int dev) -{ - int x; - - DPRINTK ("ENTER\n"); - - for (x = 0; x < num_cards; x++) - if (cards[x].mixer_oss_dev == dev) { - DPRINTK ("EXIT, returning %p\n", cards + x); - return cards + x; - } - - DPRINTK ("EXIT, returning 0\n"); - return NULL; -} - - -static int -via_ac97_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) -{ - int rc; - struct via_info *card = via_ac97_find_card_for_mixer (dev); - - DPRINTK ("ENTER\n"); - - if (card != NULL) { - rc = ac97_mixer_ioctl (&card->ac97, cmd, arg); - DPRINTK ("EXIT, returning %d\n", rc); - return rc; - } - - DPRINTK ("EXIT, returning -ENODEV\n"); - return -ENODEV; - -} - -static struct mixer_operations via_ac97_mixer_operations = -{ - "VIA82Cxxx", - "via82cxxxAC97Mixer", - via_ac97_default_mixer_ioctl -}; - -static int __init via_attach_ac97 (struct via_info *card) -{ - int mixer; - struct ac97_hwint *mdev; - - DPRINTK ("ENTER\n"); - - assert (card != NULL); - - mdev = &card->ac97; - - memset (mdev, 0, sizeof (*mdev)); - mdev->reset_device = via_ac97_reset; - mdev->read_reg = via_ac97_read_reg; - mdev->write_reg = via_ac97_write_reg; - mdev->driver_private = (void *) card; - - if (ac97_init (mdev)) { - printk (KERN_ERR PFX "Unable to init AC97\n"); - DPRINTK ("EXIT, returning -1\n"); - return -1; - } - mixer = sound_alloc_mixerdev (); - if (mixer < 0 || num_mixers >= MAX_MIXER_DEV) { - printk (KERN_ERR PFX "Unable to alloc mixerdev\n"); - DPRINTK ("EXIT, returning -1\n"); - return -1; - } - mixer_devs[mixer] = &via_ac97_mixer_operations; - card->mixer_oss_dev = mixer; - - /* Some reasonable default values. */ - ac97_set_mixer (mdev, SOUND_MIXER_VOLUME, (85 << 8) | 85); - ac97_set_mixer (mdev, SOUND_MIXER_SPEAKER, 100); - ac97_set_mixer (mdev, SOUND_MIXER_PCM, (65 << 8) | 65); - ac97_set_mixer (mdev, SOUND_MIXER_CD, (65 << 8) | 65); - - printk (KERN_INFO PFX "Initialized AC97 mixer\n"); - - card->have_ac97 = mixer; - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -static void via_unload_ac97 (struct via_info *card) -{ - DPRINTK ("ENTER\n"); - - assert (card != NULL); - - if (card->have_ac97 >= 0) - sound_unload_mixerdev (card->have_ac97); - - DPRINTK ("EXIT\n"); -} - - -#ifdef CONFIG_PROC_FS - -/**************************************************************** - * - * /proc/driver/via82cxxx/info - * - * - */ - -static int via_info_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ -#define YN(val,bit) (((val) & (bit)) ? "yes" : "no") - - int len = 0, i; - u8 r40, r41, r42, r44; - - DPRINTK ("ENTER\n"); - - len += sprintf (page+len, VIA_CARD_NAME "\n\n"); - - for (i = 0; i < num_cards; i++) { - pci_read_config_byte (cards[i].pdev, 0x40, &r40); - pci_read_config_byte (cards[i].pdev, 0x42, &r41); - pci_read_config_byte (cards[i].pdev, 0x42, &r42); - pci_read_config_byte (cards[i].pdev, 0x44, &r44); - - len += sprintf (page+len, - "40 AC97 Codec Ready: %s\n" - " AC97 Codec Low-power: %s\n" - " Secondary Codec Ready: %s\n" - - "41 AC-Link Interface Enable: %s\n" - - "42 Game port enabled: %s\n" - " SoundBlaster enabled: %s\n" - " FM enabled: %s\n" - " MIDI enabled: %s\n" - - "44 AC-Link Interface Access: %s\n" - " Secondary Codec Support: %s\n" - - "\n", - - YN (r40, VIA_CR40_AC97_READY), - YN (r40, VIA_CR40_AC97_LOW_POWER), - YN (r40, VIA_CR40_SECONDARY_READY), - - YN (r41, VIA_CR41_ACLINK_ENABLE), - - YN (r42, VIA_CR42_GAME_ENABLE), - YN (r42, VIA_CR42_SB_ENABLE), - YN (r42, VIA_CR42_FM_ENABLE), - YN (r42, VIA_CR42_MIDI_ENABLE), - - YN (r44, VIA_CR44_AC_LINK_ACCESS), - YN (r44, VIA_CR44_SECOND_CODEC_SUPPORT) - - ); - } - - DPRINTK("EXIT, returning %d\n", len); - return len; - -#undef YN -} - - -/**************************************************************** - * - * /proc/driver/via82cxxx - * - * - */ - -static int __init via_init_proc (void) -{ - DPRINTK ("ENTER\n"); - - proc_mkdir ("driver/via_audio", 0); - create_proc_read_entry ("driver/via_audio/info", 0, 0, via_info_read_proc, NULL); - - DPRINTK("EXIT\n"); - return 0; -} - - - -static void __exit via_cleanup_proc (void) -{ - DPRINTK ("ENTER\n"); - remove_proc_entry ("driver/via_audio/info", NULL); - remove_proc_entry ("driver/via_audio", NULL); - DPRINTK("EXIT\n"); -} - - -#else - -static inline int via_init_proc (void) { return 0; } -static inline void via_cleanup_proc (void) {} - -#endif /* CONFIG_PROC_FS */ - - -/**************************************************************** - * - * Legacy SoundBlaster Pro, FM support via OSS - * - * - */ - -static void __init via_attach_sb(struct address_info *hw_config) -{ - DPRINTK ("ENTER\n"); - - if(!sb_dsp_init(hw_config)) - hw_config->slots[0] = -1; - - DPRINTK("EXIT\n"); -} - - -static int __init via_probe_sb(struct address_info *hw_config) -{ - DPRINTK ("ENTER\n"); - - if (check_region(hw_config->io_base, 16)) - { - printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n", - hw_config->io_base); - return 0; - } - DPRINTK("EXIT after sb_dsp_detect\n"); - return sb_dsp_detect(hw_config, 0, 0); -} - - -static void __exit via_unload_sb(struct address_info *hw_config) -{ - DPRINTK ("ENTER\n"); - - if(hw_config->slots[0] != -1) - sb_dsp_unload(hw_config, 1); - - DPRINTK("EXIT\n"); -} - - -static const struct { - int sb_irq, - sb_dma, - midi_base, - sb_io_base; -} via_pnp_data[] __initdata = { - { 5, 0, 0x300, 0x220 }, - { 7, 1, 0x310, 0x240 }, - { 9, 2, 0x320, 0x260 }, - { 10,3, 0x330, 0x280 }, -}; - - -/**************************************************************** - * - * Chip setup and kernel registration - * - * - */ - -static int __init via82cxxx_install (struct pci_dev *pcidev) -{ - int sb_io_base; - int sb_irq; - int sb_dma; - int midi_base, rc; - u8 tmp8; - struct via_info *card = &cards[num_cards]; - - DPRINTK ("ENTER\n"); - - card->pdev = pcidev; - card->have_ac97 = -1; - - /* turn off legacy features, if not already */ - pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8); - tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE | - VIA_CR42_FM_ENABLE); - pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8); - - /* - * try to init AC97 mixer device - */ - rc = via_attach_ac97 (card); - if (rc) { - printk (KERN_WARNING PFX - "AC97 init failed, SB legacy mode only\n"); - } - - /* turn on legacy features */ - pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8); - tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE | - VIA_CR42_FM_ENABLE; - pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8); - - /* read legacy PNP info byte */ - pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8); - pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8); - - sb_irq = via_pnp_data[((tmp8 >> 6) & 0x03)].sb_irq; - sb_dma = via_pnp_data[((tmp8 >> 4) & 0x03)].sb_dma; - midi_base = via_pnp_data[((tmp8 >> 2) & 0x03)].midi_base; - sb_io_base = via_pnp_data[(tmp8 & 0x03)].sb_io_base; - - udelay(100); - - printk(KERN_INFO PFX "legacy " - "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n", - midi_base, sb_io_base, sb_irq, sb_dma); - - card->sb_data.name = VIA_CARD_NAME; - card->sb_data.card_subtype = MDL_SBPRO; - card->sb_data.io_base = sb_io_base; - card->sb_data.irq = sb_irq; - card->sb_data.dma = sb_dma; - - /* register legacy SoundBlaster Pro */ - if (!via_probe_sb (&card->sb_data)) { - printk (KERN_ERR PFX - "SB probe @ 0x%X failed, aborting\n", - sb_io_base); - DPRINTK ("EXIT, returning -1\n"); - return -1; - } - via_attach_sb (&card->sb_data); - - card->opl3_data.name = card->sb_data.name; - card->opl3_data.io_base = midi_base; - card->opl3_data.irq = -1; - - /* register legacy MIDI */ - if (!probe_uart401 (&card->opl3_data)) { - printk (KERN_WARNING PFX - "MIDI probe @ 0x%X failed, continuing\n", - midi_base); - card->opl3_data.io_base = 0; - } else { - attach_uart401 (&card->opl3_data); - } - - num_cards++; - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -/* - * This loop walks the PCI configuration database and finds where - * the sound cards are. - * - * Note - only a single PCI scan occurs, eliminating possibility - * of multiple audio chips - * - */ - -static int __init probe_via82cxxx (void) -{ - struct pci_dev *pcidev = NULL; - - DPRINTK ("ENTER\n"); - - pcidev = pci_find_device (PCI_VENDOR_ID_VIA, - PCI_DEVICE_ID_VIA_82C686_5, NULL); - - if (!pcidev || via82cxxx_install (pcidev) != 0) { - printk (KERN_ERR PFX "audio init failed\n"); - DPRINTK ("EXIT, returning -1\n"); - return -1; - } - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -/* - * This function is called when the user or kernel loads the - * module into memory. - */ - - -static int __init init_via82cxxx_module(void) -{ - u8 tmp; - int i; - const char *rev = "unknown!"; - - memset (cards, 0, sizeof (cards)); - - DPRINTK ("ENTER\n"); - - if (!pci_present ()) { - printk (KERN_DEBUG PFX "PCI not present, exiting\n"); - DPRINTK ("EXIT, returning -ENODEV\n"); - return -ENODEV; - } - - if (probe_via82cxxx() != 0) { - printk(KERN_ERR PFX "probe failed, aborting\n"); - /* XXX unload cards registered so far, if any */ - DPRINTK ("EXIT, returning -ENODEV\n"); - return -ENODEV; - } - - pci_read_config_byte (cards[0].pdev, PCI_REVISION_ID, &tmp); - for (i = 0; i < arraysize(via_chip_revs); i++) - if (via_chip_revs[i].revision == tmp) { - rev = via_chip_revs[i].rev_name; - break; - } - printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n"); - printk (KERN_INFO PFX "Chip rev %s. Features: SBPro compat%s%s\n", - rev, - cards[0].opl3_data.io_base == 0 ? "" : ", MPU-401 MIDI", - cards[0].have_ac97 == -1 ? "" : ", AC97 mixer"); - - if (via_init_proc () != 0) { - printk (KERN_WARNING PFX - "Unable to init experimental /proc, ignoring\n"); - } - - /* - * Binds us to the sound subsystem - */ - SOUND_LOCK; - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - -/* - * This is called when it is removed. It will only be removed - * when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK - * macros hide the entire work for this. - */ - -static void __exit cleanup_via82cxxx_module(void) -{ - DPRINTK("ENTER\n"); - - if (cards[0].opl3_data.io_base) - unload_uart401 (&cards[0].opl3_data); - - via_unload_sb (&cards[0].sb_data); - - via_unload_ac97 (&cards[0]); - - via_cleanup_proc (); - - /* - * Final clean up with the sound layer - */ - SOUND_LOCK_END; - - DPRINTK("EXIT\n"); -} - -module_init(init_via82cxxx_module); -module_exit(cleanup_via82cxxx_module); - diff -u --recursive --new-file v2.3.42/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.3.42/linux/drivers/sound/via82cxxx_audio.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/via82cxxx_audio.c Wed Feb 9 18:54:11 2000 @@ -0,0 +1,721 @@ +/* + * Support for VIA 82Cxxx Audio Codecs + * Copyright 1999,2000 Jeff Garzik + * + * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2. + * See the "COPYING" file distributed with this software for more info. + * + * Documentation for this driver available as + * linux/Documentation/sound/via82cxxx.txt. + * + * Since the mixer is called from the OSS glue the kernel lock is always held + * on our AC97 mixing + */ + + +#define VIA_VERSION "1.1.2.1" + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sound_config.h" +#include "soundmodule.h" +#include "sb.h" +#include "ac97.h" + +#ifndef SOUND_LOCK +#define SOUND_LOCK do {} while (0) +#define SOUND_LOCK_END do {} while (0) +#endif + +#define VIA_DEBUG 0 /* define to 1 to enable debugging output and checks */ +#if VIA_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define VIA_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ +#if VIA_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +#define MAX_CARDS 2 + +#define LINE_SIZE 10 + +#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION +#define VIA_MODULE_NAME "via_audio" +#define PFX VIA_MODULE_NAME ": " + +#define VIA_COUNTER_LIMIT 100000 + +/* 82C686 function 5 (audio codec) PCI configuration registers */ +#define VIA_FUNC_ENABLE 0x42 +#define VIA_PNP_CONTROL 0x43 +#define VIA_AC97_CTRL 0x80 + +/* PCI configuration register bits and masks */ +#define VIA_CR40_AC97_READY 0x01 +#define VIA_CR40_AC97_LOW_POWER 0x02 +#define VIA_CR40_SECONDARY_READY 0x04 + +#define VIA_CR41_ACLINK_ENABLE 0x80 + +#define VIA_CR42_SB_ENABLE 0x01 +#define VIA_CR42_MIDI_ENABLE 0x02 +#define VIA_CR42_FM_ENABLE 0x04 +#define VIA_CR42_GAME_ENABLE 0x08 + +#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6) +#define VIA_CR44_AC_LINK_ACCESS (1 << 7) + +#define VIA_CR80_FIRST_CODEC 0 +#define VIA_CR80_SECOND_CODEC (1 << 30) +#define VIA_CR80_FIRST_CODEC_VALID (1 << 25) +#define VIA_CR80_SECOND_CODEC_VALID (1 << 27) +#define VIA_CR80_BUSY (1 << 24) +#define VIA_CR80_READ_MODE (1 << 23) +#define VIA_CR80_WRITE_MODE 0 +#define VIA_CR80_REG_IDX(idx) (((idx) & 0x7E) << 16) + +struct via_info { + struct address_info sb_data; + struct address_info opl3_data; + struct pci_dev *pdev; + struct ac97_hwint ac97; + int mixer_oss_dev; + int have_ac97; +}; +static struct via_info cards [MAX_CARDS]; +static unsigned num_cards = 0; + + +static const struct { + int revision; + const char *rev_name; +} via_chip_revs[] __initdata = { + { 0x10, "A" }, + { 0x11, "B" }, + { 0x12, "C" }, + { 0x13, "D" }, + { 0x14, "E" }, + { 0x20, "H" }, +}; + +static inline void via_ac97_write32 (struct pci_dev *pdev, int port, u32 data) +{ + struct resource *rsrc = &pdev->resource[0]; + outw ((u16)data,rsrc->start+port); + outw ((u16)(data>>16),rsrc->start+port+2); +} + +static inline u32 via_ac97_read32 (struct pci_dev *pdev, int port) +{ + struct resource *rsrc = &pdev->resource[0]; + return + ((u32)inw (rsrc->start+port)) | + (((u32)inw (rsrc->start+port+2)) << 16); +} + +/**************************************************************** + * + * Intel Audio Codec '97 interface + * + * + */ + +static inline void via_ac97_wait_idle (struct pci_dev *pdev) +{ + u32 tmp; + int counter = VIA_COUNTER_LIMIT; + + DPRINTK ("ENTER\n"); + + assert (pdev != NULL); + + do { + tmp = via_ac97_read32 (pdev,VIA_AC97_CTRL); + } while ((tmp & VIA_CR80_BUSY) && (counter-- > 0)); + + DPRINTK ("EXIT%s\n", counter > 0 ? "" : ", counter limit reached"); +} + + +static int via_ac97_read_reg (struct ac97_hwint *dev, u8 reg) +{ + u32 data; + struct via_info *card; + struct pci_dev *pdev; + + DPRINTK ("ENTER\n"); + + assert (dev != NULL); + assert (dev->driver_private != NULL); + + card = (struct via_info *) dev->driver_private; + pdev = card->pdev; + assert (pdev != NULL); + + via_ac97_wait_idle (pdev); + data = VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID | + VIA_CR80_READ_MODE | VIA_CR80_REG_IDX(reg); + via_ac97_write32 (pdev,VIA_AC97_CTRL,data); + via_ac97_wait_idle (pdev); + data = via_ac97_read32 (pdev,VIA_AC97_CTRL); + +#if 0 + if (! (data & VIA_CR80_FIRST_CODEC_VALID)) { + DPRINTK ("EXIT, first codec not valid, returning -1\n"); + return -1; + } +#endif + + DPRINTK ("EXIT, returning %d\n", data & 0xFFFF); + return data & 0xFFFF; +} + + +static int via_ac97_write_reg (struct ac97_hwint *dev, u8 reg, u16 value) +{ + u32 data; + struct via_info *card; + struct pci_dev *pdev; + + DPRINTK ("ENTER\n"); + + assert (dev != NULL); + assert (dev->driver_private != NULL); + + card = (struct via_info *) dev->driver_private; + pdev = card->pdev; + assert (pdev != NULL); + + via_ac97_wait_idle (pdev); + data = VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID | + VIA_CR80_WRITE_MODE | VIA_CR80_REG_IDX(reg) | value; + via_ac97_write32 (pdev,VIA_AC97_CTRL,data); + +#if 0 + if (! (data & VIA_CR80_FIRST_CODEC_VALID)) { + DPRINTK ("EXIT, first codec invalid, returning -1\n"); + return -1; + } +#endif + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +static int via_ac97_reset (struct ac97_hwint *dev) +{ + struct via_info *card; + struct pci_dev *pdev; + + DPRINTK ("ENTER\n"); + + assert (dev != NULL); + assert (dev->driver_private != NULL); + + card = (struct via_info *) dev->driver_private; + pdev = card->pdev; + assert (pdev != NULL); + + pci_write_config_word (pdev, PCI_COMMAND, PCI_COMMAND_IO); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +static struct via_info *via_ac97_find_card_for_mixer (int dev) +{ + int x; + + DPRINTK ("ENTER\n"); + + for (x = 0; x < num_cards; x++) + if (cards[x].mixer_oss_dev == dev) { + DPRINTK ("EXIT, returning %p\n", cards + x); + return cards + x; + } + + DPRINTK ("EXIT, returning 0\n"); + return NULL; +} + + +static int +via_ac97_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +{ + int rc; + struct via_info *card = via_ac97_find_card_for_mixer (dev); + + DPRINTK ("ENTER\n"); + + if (card != NULL) { + rc = ac97_mixer_ioctl (&card->ac97, cmd, arg); + DPRINTK ("EXIT, returning %d\n", rc); + return rc; + } + + DPRINTK ("EXIT, returning -ENODEV\n"); + return -ENODEV; + +} + +static struct mixer_operations via_ac97_mixer_operations = +{ + "VIA82Cxxx", + "via82cxxxAC97Mixer", + via_ac97_default_mixer_ioctl +}; + +static int __init via_attach_ac97 (struct via_info *card) +{ + int mixer; + struct ac97_hwint *mdev; + + DPRINTK ("ENTER\n"); + + assert (card != NULL); + + mdev = &card->ac97; + + memset (mdev, 0, sizeof (*mdev)); + mdev->reset_device = via_ac97_reset; + mdev->read_reg = via_ac97_read_reg; + mdev->write_reg = via_ac97_write_reg; + mdev->driver_private = (void *) card; + + if (ac97_init (mdev)) { + printk (KERN_ERR PFX "Unable to init AC97\n"); + DPRINTK ("EXIT, returning -1\n"); + return -1; + } + mixer = sound_alloc_mixerdev (); + if (mixer < 0 || num_mixers >= MAX_MIXER_DEV) { + printk (KERN_ERR PFX "Unable to alloc mixerdev\n"); + DPRINTK ("EXIT, returning -1\n"); + return -1; + } + mixer_devs[mixer] = &via_ac97_mixer_operations; + card->mixer_oss_dev = mixer; + + /* Some reasonable default values. */ + ac97_set_mixer (mdev, SOUND_MIXER_VOLUME, (85 << 8) | 85); + ac97_set_mixer (mdev, SOUND_MIXER_SPEAKER, 100); + ac97_set_mixer (mdev, SOUND_MIXER_PCM, (65 << 8) | 65); + ac97_set_mixer (mdev, SOUND_MIXER_CD, (65 << 8) | 65); + + printk (KERN_INFO PFX "Initialized AC97 mixer\n"); + + card->have_ac97 = mixer; + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +static void via_unload_ac97 (struct via_info *card) +{ + DPRINTK ("ENTER\n"); + + assert (card != NULL); + + if (card->have_ac97 >= 0) + sound_unload_mixerdev (card->have_ac97); + + DPRINTK ("EXIT\n"); +} + + +#ifdef CONFIG_PROC_FS + +/**************************************************************** + * + * /proc/driver/via82cxxx/info + * + * + */ + +static int via_info_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ +#define YN(val,bit) (((val) & (bit)) ? "yes" : "no") + + int len = 0, i; + u8 r40, r41, r42, r44; + + DPRINTK ("ENTER\n"); + + len += sprintf (page+len, VIA_CARD_NAME "\n\n"); + + for (i = 0; i < num_cards; i++) { + pci_read_config_byte (cards[i].pdev, 0x40, &r40); + pci_read_config_byte (cards[i].pdev, 0x42, &r41); + pci_read_config_byte (cards[i].pdev, 0x42, &r42); + pci_read_config_byte (cards[i].pdev, 0x44, &r44); + + len += sprintf (page+len, + "40 AC97 Codec Ready: %s\n" + " AC97 Codec Low-power: %s\n" + " Secondary Codec Ready: %s\n" + + "41 AC-Link Interface Enable: %s\n" + + "42 Game port enabled: %s\n" + " SoundBlaster enabled: %s\n" + " FM enabled: %s\n" + " MIDI enabled: %s\n" + + "44 AC-Link Interface Access: %s\n" + " Secondary Codec Support: %s\n" + + "\n", + + YN (r40, VIA_CR40_AC97_READY), + YN (r40, VIA_CR40_AC97_LOW_POWER), + YN (r40, VIA_CR40_SECONDARY_READY), + + YN (r41, VIA_CR41_ACLINK_ENABLE), + + YN (r42, VIA_CR42_GAME_ENABLE), + YN (r42, VIA_CR42_SB_ENABLE), + YN (r42, VIA_CR42_FM_ENABLE), + YN (r42, VIA_CR42_MIDI_ENABLE), + + YN (r44, VIA_CR44_AC_LINK_ACCESS), + YN (r44, VIA_CR44_SECOND_CODEC_SUPPORT) + + ); + } + + DPRINTK("EXIT, returning %d\n", len); + return len; + +#undef YN +} + + +/**************************************************************** + * + * /proc/driver/via82cxxx + * + * + */ + +static int __init via_init_proc (void) +{ + DPRINTK ("ENTER\n"); + + proc_mkdir ("driver/via_audio", 0); + create_proc_read_entry ("driver/via_audio/info", 0, 0, via_info_read_proc, NULL); + + DPRINTK("EXIT\n"); + return 0; +} + + + +static void __exit via_cleanup_proc (void) +{ + DPRINTK ("ENTER\n"); + remove_proc_entry ("driver/via_audio/info", NULL); + remove_proc_entry ("driver/via_audio", NULL); + DPRINTK("EXIT\n"); +} + + +#else + +static inline int via_init_proc (void) { return 0; } +static inline void via_cleanup_proc (void) {} + +#endif /* CONFIG_PROC_FS */ + + +/**************************************************************** + * + * Legacy SoundBlaster Pro, FM support via OSS + * + * + */ + +static void __init via_attach_sb(struct address_info *hw_config) +{ + DPRINTK ("ENTER\n"); + + if(!sb_dsp_init(hw_config)) + hw_config->slots[0] = -1; + + DPRINTK("EXIT\n"); +} + + +static int __init via_probe_sb(struct address_info *hw_config) +{ + DPRINTK ("ENTER\n"); + + if (check_region(hw_config->io_base, 16)) + { + printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n", + hw_config->io_base); + return 0; + } + DPRINTK("EXIT after sb_dsp_detect\n"); + return sb_dsp_detect(hw_config, 0, 0); +} + + +static void __exit via_unload_sb(struct address_info *hw_config) +{ + DPRINTK ("ENTER\n"); + + if(hw_config->slots[0] != -1) + sb_dsp_unload(hw_config, 1); + + DPRINTK("EXIT\n"); +} + + +static const struct { + int sb_irq, + sb_dma, + midi_base, + sb_io_base; +} via_pnp_data[] __initdata = { + { 5, 0, 0x300, 0x220 }, + { 7, 1, 0x310, 0x240 }, + { 9, 2, 0x320, 0x260 }, + { 10,3, 0x330, 0x280 }, +}; + + +/**************************************************************** + * + * Chip setup and kernel registration + * + * + */ + +static int __init via82cxxx_install (struct pci_dev *pcidev) +{ + int sb_io_base; + int sb_irq; + int sb_dma; + int midi_base, rc; + u8 tmp8; + struct via_info *card = &cards[num_cards]; + + DPRINTK ("ENTER\n"); + + card->pdev = pcidev; + card->have_ac97 = -1; + + /* turn off legacy features, if not already */ + pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8); + tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE | + VIA_CR42_FM_ENABLE); + pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8); + + /* + * try to init AC97 mixer device + */ + rc = via_attach_ac97 (card); + if (rc) { + printk (KERN_WARNING PFX + "AC97 init failed, SB legacy mode only\n"); + } + + /* turn on legacy features */ + pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8); + tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE | + VIA_CR42_FM_ENABLE; + pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8); + + /* read legacy PNP info byte */ + pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8); + pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8); + + sb_irq = via_pnp_data[((tmp8 >> 6) & 0x03)].sb_irq; + sb_dma = via_pnp_data[((tmp8 >> 4) & 0x03)].sb_dma; + midi_base = via_pnp_data[((tmp8 >> 2) & 0x03)].midi_base; + sb_io_base = via_pnp_data[(tmp8 & 0x03)].sb_io_base; + + udelay(100); + + printk(KERN_INFO PFX "legacy " + "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n", + midi_base, sb_io_base, sb_irq, sb_dma); + + card->sb_data.name = VIA_CARD_NAME; + card->sb_data.card_subtype = MDL_SBPRO; + card->sb_data.io_base = sb_io_base; + card->sb_data.irq = sb_irq; + card->sb_data.dma = sb_dma; + + /* register legacy SoundBlaster Pro */ + if (!via_probe_sb (&card->sb_data)) { + printk (KERN_ERR PFX + "SB probe @ 0x%X failed, aborting\n", + sb_io_base); + DPRINTK ("EXIT, returning -1\n"); + return -1; + } + via_attach_sb (&card->sb_data); + + card->opl3_data.name = card->sb_data.name; + card->opl3_data.io_base = midi_base; + card->opl3_data.irq = -1; + + /* register legacy MIDI */ + if (!probe_uart401 (&card->opl3_data)) { + printk (KERN_WARNING PFX + "MIDI probe @ 0x%X failed, continuing\n", + midi_base); + card->opl3_data.io_base = 0; + } else { + attach_uart401 (&card->opl3_data); + } + + num_cards++; + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * This loop walks the PCI configuration database and finds where + * the sound cards are. + * + * Note - only a single PCI scan occurs, eliminating possibility + * of multiple audio chips + * + */ + +static int __init probe_via82cxxx (void) +{ + struct pci_dev *pcidev = NULL; + + DPRINTK ("ENTER\n"); + + pcidev = pci_find_device (PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C686_5, NULL); + + if (!pcidev || via82cxxx_install (pcidev) != 0) { + printk (KERN_ERR PFX "audio init failed\n"); + DPRINTK ("EXIT, returning -1\n"); + return -1; + } + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * This function is called when the user or kernel loads the + * module into memory. + */ + + +static int __init init_via82cxxx_module(void) +{ + u8 tmp; + int i; + const char *rev = "unknown!"; + + memset (cards, 0, sizeof (cards)); + + DPRINTK ("ENTER\n"); + + if (!pci_present ()) { + printk (KERN_DEBUG PFX "PCI not present, exiting\n"); + DPRINTK ("EXIT, returning -ENODEV\n"); + return -ENODEV; + } + + if (probe_via82cxxx() != 0) { + printk(KERN_ERR PFX "probe failed, aborting\n"); + /* XXX unload cards registered so far, if any */ + DPRINTK ("EXIT, returning -ENODEV\n"); + return -ENODEV; + } + + pci_read_config_byte (cards[0].pdev, PCI_REVISION_ID, &tmp); + for (i = 0; i < arraysize(via_chip_revs); i++) + if (via_chip_revs[i].revision == tmp) { + rev = via_chip_revs[i].rev_name; + break; + } + printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n"); + printk (KERN_INFO PFX "Chip rev %s. Features: SBPro compat%s%s\n", + rev, + cards[0].opl3_data.io_base == 0 ? "" : ", MPU-401 MIDI", + cards[0].have_ac97 == -1 ? "" : ", AC97 mixer"); + + if (via_init_proc () != 0) { + printk (KERN_WARNING PFX + "Unable to init experimental /proc, ignoring\n"); + } + + /* + * Binds us to the sound subsystem + */ + SOUND_LOCK; + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + +/* + * This is called when it is removed. It will only be removed + * when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK + * macros hide the entire work for this. + */ + +static void __exit cleanup_via82cxxx_module(void) +{ + DPRINTK("ENTER\n"); + + if (cards[0].opl3_data.io_base) + unload_uart401 (&cards[0].opl3_data); + + via_unload_sb (&cards[0].sb_data); + + via_unload_ac97 (&cards[0]); + + via_cleanup_proc (); + + /* + * Final clean up with the sound layer + */ + SOUND_LOCK_END; + + DPRINTK("EXIT\n"); +} + +module_init(init_via82cxxx_module); +module_exit(cleanup_via82cxxx_module); + diff -u --recursive --new-file v2.3.42/linux/drivers/sound/vwsnd.c linux/drivers/sound/vwsnd.c --- v2.3.42/linux/drivers/sound/vwsnd.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sound/vwsnd.c Wed Feb 9 11:42:35 2000 @@ -3029,19 +3029,14 @@ } static struct file_operations vwsnd_audio_fops = { - &vwsnd_audio_llseek, - &vwsnd_audio_read, - &vwsnd_audio_write, - NULL, /* readdir */ - &vwsnd_audio_poll, - &vwsnd_audio_ioctl, - &vwsnd_audio_mmap, - &vwsnd_audio_open, - NULL, /* flush */ - &vwsnd_audio_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: vwsnd_audio_llseek, + read: vwsnd_audio_read, + write: vwsnd_audio_write, + poll: vwsnd_audio_poll, + ioctl: vwsnd_audio_ioctl, + mmap: vwsnd_audio_mmap, + open: vwsnd_audio_open, + release: vwsnd_audio_release, }; /*****************************************************************************/ @@ -3238,19 +3233,10 @@ } static struct file_operations vwsnd_mixer_fops = { - &vwsnd_mixer_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &vwsnd_mixer_ioctl, - NULL, /* mmap */ - &vwsnd_mixer_open, - NULL, /* flush */ - &vwsnd_mixer_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: vwsnd_mixer_llseek, + ioctl: vwsnd_mixer_ioctl, + open: vwsnd_mixer_open, + release: vwsnd_mixer_release, }; /*****************************************************************************/ diff -u --recursive --new-file v2.3.42/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.3.42/linux/drivers/sound/wavfront.c Fri Jan 7 19:13:22 2000 +++ linux/drivers/sound/wavfront.c Wed Feb 9 11:42:35 2000 @@ -2002,19 +2002,10 @@ } static /*const*/ struct file_operations wavefront_fops = { - &wavefront_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &wavefront_ioctl, - NULL, /* mmap */ - &wavefront_open, - NULL, /* flush */ - &wavefront_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: wavefront_llseek, + ioctl: wavefront_ioctl, + open: wavefront_open, + release: wavefront_release, }; diff -u --recursive --new-file v2.3.42/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c --- v2.3.42/linux/drivers/telephony/ixj.c Tue Jan 11 22:31:41 2000 +++ linux/drivers/telephony/ixj.c Wed Feb 9 11:42:35 2000 @@ -3922,20 +3922,12 @@ struct file_operations ixj_fops = { - NULL, /* ixj_lseek */ - ixj_enhanced_read, - ixj_enhanced_write, - NULL, /* ixj_readdir */ - ixj_poll, - ixj_ioctl, - NULL, /* ixj_mmap */ -// ixj_open, - NULL, /* ixj_open */ - NULL, /* ixj_flush */ - ixj_release, - NULL, /* ixj_fsync */ - ixj_fasync, /* ixj_fasync */ - NULL /* lock */ + read: ixj_enhanced_read, + write: ixj_enhanced_write, + poll: ixj_poll, + ioctl: ixj_ioctl, + release: ixj_release, + fasync: ixj_fasync, }; static int ixj_linetest(int board) diff -u --recursive --new-file v2.3.42/linux/drivers/telephony/phonedev.c linux/drivers/telephony/phonedev.c --- v2.3.42/linux/drivers/telephony/phonedev.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/telephony/phonedev.c Wed Feb 9 11:42:35 2000 @@ -112,16 +112,7 @@ static struct file_operations phone_fops = { - NULL, - NULL, - NULL, - NULL, /* readdir */ - NULL, - NULL, - NULL, - phone_open, - NULL, /* flush */ - NULL + open: phone_open, }; /* diff -u --recursive --new-file v2.3.42/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.42/linux/drivers/usb/Config.in Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/Config.in Tue Feb 8 17:11:13 2000 @@ -10,6 +10,9 @@ comment 'USB Controllers' dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB + if [ "$CONFIG_USB_UHCI_ALT" != "n" ]; then + bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE + fi dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB comment 'Miscellaneous USB options' @@ -26,6 +29,7 @@ bool ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR bool ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI + bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA bool ' USB Belkin Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN bool ' USB Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PERACOM fi diff -u --recursive --new-file v2.3.42/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.3.42/linux/drivers/usb/Makefile Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/Makefile Tue Feb 8 17:07:22 2000 @@ -90,8 +90,8 @@ # Translate to Rules.make lists. -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) +O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) diff -u --recursive --new-file v2.3.42/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.3.42/linux/drivers/usb/acm.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/acm.c Wed Feb 9 11:51:13 2000 @@ -223,21 +223,25 @@ if (!ACM_READY(acm)) return; + if (urb->status) + dbg("nonzero read bulk status received: %d", urb->status); + if (!urb->status & !acm->throttle) { for (i = 0; i < urb->actual_length && !acm->throttle; i++) tty_insert_flip_char(tty, data[i], 0); tty_flip_buffer_push(tty); - } else - dbg("nonzero read bulk status received: %d", urb->status); + } - if (!acm->throttle) { - urb->actual_length = 0; - if (usb_submit_urb(urb)) - dbg("failed resubmitting read urb"); - } else { + if (acm->throttle) { memmove(data, data + i, urb->actual_length - i); urb->actual_length -= i; + return; } + + urb->actual_length = 0; + + if (usb_submit_urb(urb)) + dbg("failed resubmitting read urb"); } static void acm_write_bulk(struct urb *urb) diff -u --recursive --new-file v2.3.42/linux/drivers/usb/audio.c linux/drivers/usb/audio.c --- v2.3.42/linux/drivers/usb/audio.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/audio.c Wed Feb 9 11:42:35 2000 @@ -258,7 +258,6 @@ struct usb_audiodev { struct list_head list; struct usb_audio_state *state; - int remove_pending; /* soundcore stuff */ int dev_audio; @@ -838,8 +837,6 @@ #if 0 printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags); #endif - if (as->remove_pending) - return; if (urb == &u->durb[0].urb) mask = FLG_URB0RUNNING; else if (urb == &u->durb[1].urb) @@ -904,9 +901,6 @@ #if 0 printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags); #endif - if (as->remove_pending) - return; - if (urb == &u->surb[0].urb) mask = FLG_SYNC0RUNNING; else if (urb == &u->surb[1].urb) @@ -1266,8 +1260,6 @@ #if 0 printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags); #endif - if (as->remove_pending) - return; if (urb == &u->surb[0].urb) mask = FLG_SYNC0RUNNING; else if (urb == &u->surb[1].urb) @@ -1462,6 +1454,7 @@ d->srate = fmt->sratelo; if (d->srate > fmt->sratehi) d->srate = fmt->sratehi; +printk(KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting); if (usb_set_interface(dev, alts->bInterfaceNumber, fmt->altsetting) < 0) { printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", dev->devnum, u->interface, fmt->altsetting); @@ -1527,13 +1520,13 @@ u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].bEndpointAddress & 0xf); u->syncpipe = u->syncinterval = 0; if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x04) { - +#if 0 printk(KERN_DEBUG "bNumEndpoints 0x%02x endpoint[1].bmAttributes 0x%02x\n" KERN_DEBUG "endpoint[1].bSynchAddress 0x%02x endpoint[1].bEndpointAddress 0x%02x\n" KERN_DEBUG "endpoint[0].bSynchAddress 0x%02x\n", alts->bNumEndpoints, alts->endpoint[1].bmAttributes, alts->endpoint[1].bSynchAddress, alts->endpoint[1].bEndpointAddress, alts->endpoint[0].bSynchAddress); - +#endif if (alts->bNumEndpoints < 2 || alts->endpoint[1].bmAttributes != 0x01 || alts->endpoint[1].bSynchAddress != 0 || @@ -1545,14 +1538,11 @@ u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf); u->syncinterval = alts->endpoint[1].bRefresh; } - - printk(KERN_DEBUG "datapipe 0x%x syncpipe 0x%x\n", u->datapipe, u->syncpipe); - - if (d->srate < fmt->sratelo) d->srate = fmt->sratelo; if (d->srate > fmt->sratehi) d->srate = fmt->sratehi; +printk(KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting); if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) { printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n", dev->devnum, u->interface, fmt->altsetting); @@ -1904,19 +1894,10 @@ } static /*const*/ struct file_operations usb_mixer_fops = { - &usb_audio_llseek, - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - &usb_audio_ioctl_mixdev, - NULL, /* mmap */ - &usb_audio_open_mixdev, - NULL, /* flush */ - &usb_audio_release_mixdev, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: usb_audio_llseek, + ioctl: usb_audio_ioctl_mixdev, + open: usb_audio_open_mixdev, + release: usb_audio_release_mixdev, }; /* --------------------------------------------------------------------- */ @@ -2473,7 +2454,6 @@ file->private_data = as; as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); s->count++; - as->remove_pending=0; MOD_INC_USE_COUNT; up(&open_sem); return 0; @@ -2515,19 +2495,14 @@ } static /*const*/ struct file_operations usb_audio_fops = { - &usb_audio_llseek, - &usb_audio_read, - &usb_audio_write, - NULL, /* readdir */ - &usb_audio_poll, - &usb_audio_ioctl, - &usb_audio_mmap, - &usb_audio_open, - NULL, /* flush */ - &usb_audio_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ + llseek: usb_audio_llseek, + read: usb_audio_read, + write: usb_audio_write, + poll: usb_audio_poll, + ioctl: usb_audio_ioctl, + mmap: usb_audio_mmap, + open: usb_audio_open, + release: usb_audio_release, }; /* --------------------------------------------------------------------- */ @@ -3143,14 +3118,20 @@ } if (state->nrchannels > 2) printk(KERN_WARNING "usbaudio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]); - if (ftr[0] < 7+ftr[5]*(1+state->nrchannels)) { - printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", ftr[3]); - return; + if (state->nrchannels == 1 && ftr[0] == 7+ftr[5]) { + printk(KERN_WARNING "usbaudio: workaround for broken Philips Camera Microphone descriptor enabled\n"); + mchftr = ftr[6]; + chftr = 0; + } else { + if (ftr[0] < 7+ftr[5]*(1+state->nrchannels)) { + printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", ftr[3]); + return; + } + mchftr = ftr[6]; + chftr = ftr[6+ftr[5]]; + if (state->nrchannels > 1) + chftr &= ftr[6+2*ftr[5]]; } - mchftr = ftr[6]; - chftr = ftr[6+ftr[5]]; - if (state->nrchannels > 1) - chftr &= ftr[6+2*ftr[5]]; /* volume control */ if (chftr & 2) { ch = getmixchannel(state, getvolchannel(state)); diff -u --recursive --new-file v2.3.42/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c --- v2.3.42/linux/drivers/usb/cpia.c Mon Dec 20 18:48:22 1999 +++ linux/drivers/usb/cpia.c Mon Feb 7 19:13:37 2000 @@ -2,10 +2,8 @@ * USB CPiA Video Camera driver * * Supports CPiA based Video Cameras. Many manufacturers use this chipset. - * There's a good chance, if you have a USB video camera, it's a CPiA based - * one. * - * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com * (C) Copyright 1999 Randy Dunlap */ @@ -496,7 +494,6 @@ copylen = 0; wakeup: - cpia->curframe = -1; /* This will cause the process to request another frame. */ @@ -555,9 +552,8 @@ struct cpia_sbuf *sbuf; int i; -#if 0 -printk("cpia_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length); -#endif + if (!cpia->dev) + return; if (!cpia->streaming) { if (debug >= 1) @@ -566,7 +562,6 @@ } sbuf = &cpia->sbuf[cpia->cursbuf]; - // usb_kill_isoc(sbuf->isodesc); /* Copy the data received into our scratch buffer */ len = cpia_compress_isochronous(cpia, urb); @@ -584,18 +579,15 @@ sbuf->urb->iso_frame_desc[i].status = 0; sbuf->urb->iso_frame_desc[i].actual_length = 0; } + /* Move to the next sbuf */ cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF; - /* Reschedule this block of Isochronous desc */ - // usb_run_isoc(sbuf->isodesc, cpia->sbuf[cpia->cursbuf].isodesc); - return; } static int cpia_init_isoc(struct usb_cpia *cpia) { - struct usb_device *dev = cpia->dev; urb_t *urb; int fx, err; @@ -611,7 +603,6 @@ } /* We double buffer the Iso lists */ -// err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC, cpia, &cpia->sbuf[0].isodesc); urb = usb_alloc_urb(FRAMES_PER_DESC); if (!urb) { @@ -620,9 +611,9 @@ return -ENOMEM; } cpia->sbuf[0].urb = urb; - urb->dev = dev; + urb->dev = cpia->dev; urb->context = cpia; - urb->pipe = usb_rcvisocpipe(dev, 1); + urb->pipe = usb_rcvisocpipe(cpia->dev, 1); urb->transfer_flags = USB_ISO_ASAP; urb->transfer_buffer = cpia->sbuf[0].data; urb->complete = cpia_isoc_irq; @@ -639,9 +630,9 @@ return -ENOMEM; } cpia->sbuf[1].urb = urb; - urb->dev = dev; + urb->dev = cpia->dev; urb->context = cpia; - urb->pipe = usb_rcvisocpipe(dev, 1); + urb->pipe = usb_rcvisocpipe(cpia->dev, 1); urb->transfer_flags = USB_ISO_ASAP; urb->transfer_buffer = cpia->sbuf[1].data; urb->complete = cpia_isoc_irq; @@ -657,11 +648,11 @@ err = usb_submit_urb(cpia->sbuf[0].urb); if (err) - printk(KERN_ERR "cpia_init_isoc: usb_run_isoc(0) ret %d\n", + printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(0) ret %d\n", err); err = usb_submit_urb(cpia->sbuf[1].urb); if (err) - printk(KERN_ERR "cpia_init_isoc: usb_run_isoc(1) ret %d\n", + printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(1) ret %d\n", err); cpia->streaming = 1; @@ -671,7 +662,7 @@ static void cpia_stop_isoc(struct usb_cpia *cpia) { - if (!cpia->streaming) + if (!cpia->streaming || !cpia->dev) return; /* Turn off continuous grab */ @@ -686,15 +677,21 @@ return /* -EINVAL */; } - /* Unschedule all of the iso td's */ - usb_unlink_urb(cpia->sbuf[1].urb); - usb_unlink_urb(cpia->sbuf[0].urb); - cpia->streaming = 0; - /* Delete them all */ - usb_free_urb(cpia->sbuf[1].urb); - usb_free_urb(cpia->sbuf[0].urb); + /* Unschedule all of the iso td's */ + if (cpia->sbuf[1].urb) { + cpia->sbuf[1].urb->next = NULL; + usb_unlink_urb(cpia->sbuf[1].urb); + usb_free_urb(cpia->sbuf[1].urb); + cpia->sbuf[1].urb = NULL; + } + if (cpia->sbuf[0].urb) { + cpia->sbuf[0].urb->next = NULL; + usb_unlink_urb(cpia->sbuf[0].urb); + usb_free_urb(cpia->sbuf[0].urb); + cpia->sbuf[0].urb = NULL; + } } static int cpia_new_frame(struct usb_cpia *cpia, int framenum) @@ -702,6 +699,9 @@ struct cpia_frame *frame; int width, height; + if (!cpia->dev) + return -1; + /* If we're not grabbing a frame right now and the other frame is */ /* ready to be grabbed into, then use it instead */ if (cpia->curframe == -1) { @@ -833,6 +833,11 @@ kfree(cpia->sbuf[0].data); up(&cpia->lock); + + if (!cpia->dev) { + video_unregister_device(&cpia->vdev); + kfree(cpia); + } } static int cpia_init_done(struct video_device *dev) @@ -849,6 +854,9 @@ { struct usb_cpia *cpia = (struct usb_cpia *)dev; + if (!cpia->dev) + return -EIO; + switch (cmd) { case VIDIOCGCAP: { @@ -1025,10 +1033,10 @@ case FRAME_GRABBING: case FRAME_ERROR: redo: + if (!cpia->dev) + return -EIO; + do { -#if 0 - init_waitqueue_head(&cpia->frame[frame].wq); -#endif interruptible_sleep_on(&cpia->frame[frame].wq); if (signal_pending(current)) return -EINTR; @@ -1095,6 +1103,9 @@ if (!dev || !buf) return -EFAULT; + if (!cpia->dev) + return -EIO; + /* See if a frame is completed, then use it. */ if (cpia->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ frmx = 0; @@ -1120,6 +1131,9 @@ frame = &cpia->frame[frmx]; restart: + if (!cpia->dev) + return -EIO; + while (frame->grabstate == FRAME_GRABBING) { interruptible_sleep_on(&frame->wq); if (signal_pending(current)) @@ -1168,6 +1182,9 @@ unsigned long start = (unsigned long)adr; unsigned long page, pos; + if (!cpia->dev) + return -EIO; + if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) return -EINVAL; @@ -1326,23 +1343,56 @@ cpia->iface = interface->bInterfaceNumber; if (!usb_cpia_configure(cpia)) { - cpia->user=0; - init_MUTEX(&cpia->lock); /* to 1 == available */ - return cpia; - } else return NULL; + cpia->user=0; + init_MUTEX(&cpia->lock); /* to 1 == available */ + + return cpia; + } else + return NULL; } static void cpia_disconnect(struct usb_device *dev, void *ptr) { struct usb_cpia *cpia = (struct usb_cpia *) ptr; - video_unregister_device(&cpia->vdev); + /* We don't want people trying to open up the device */ + if (!cpia->user) + video_unregister_device(&cpia->vdev); usb_driver_release_interface(&cpia_driver, &cpia->dev->actconfig->interface[0]); + cpia->dev = NULL; + cpia->frame[0].grabstate = FRAME_ERROR; + cpia->frame[1].grabstate = FRAME_ERROR; + cpia->curframe = -1; + + /* This will cause the process to request another frame. */ + if (waitqueue_active(&cpia->frame[0].wq)) + wake_up_interruptible(&cpia->frame[0].wq); + + if (waitqueue_active(&cpia->frame[1].wq)) + wake_up_interruptible(&cpia->frame[1].wq); + + cpia->streaming = 0; + + /* Unschedule all of the iso td's */ + if (cpia->sbuf[1].urb) { + cpia->sbuf[1].urb->next = NULL; + usb_unlink_urb(cpia->sbuf[1].urb); + usb_free_urb(cpia->sbuf[1].urb); + cpia->sbuf[1].urb = NULL; + } + if (cpia->sbuf[0].urb) { + cpia->sbuf[0].urb->next = NULL; + usb_unlink_urb(cpia->sbuf[0].urb); + usb_free_urb(cpia->sbuf[0].urb); + cpia->sbuf[0].urb = NULL; + } + /* Free the memory */ - kfree(cpia); + if (!cpia->user) + kfree(cpia); } static struct usb_driver cpia_driver = { diff -u --recursive --new-file v2.3.42/linux/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c --- v2.3.42/linux/drivers/usb/dabusb.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/dabusb.c Wed Feb 9 15:20:13 2000 @@ -21,7 +21,7 @@ * * * - * $Id: dabusb.c,v 1.30 1999/12/17 17:50:58 fliegl Exp $ + * $Id: dabusb.c,v 1.45 2000/01/31 10:23:44 fliegl Exp $ * */ @@ -38,26 +38,22 @@ #include #include -#undef DEBUG -#undef DEBUG_ALL - #include "usb.h" #include "dabusb.h" #include "dabfirmware.h" + /* --------------------------------------------------------------------- */ #define NRDABUSB 4 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define __init -#define __exit -#endif - /*-------------------------------------------------------------------*/ + static dabusb_t dabusb[NRDABUSB]; static int buffers = 256; + /*-------------------------------------------------------------------*/ + static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src) { unsigned long flags; @@ -79,7 +75,7 @@ return ret; } /*-------------------------------------------------------------------*/ -#ifdef DEBUG +#ifdef DEBUG static void dump_urb (purb_t purb) { dbg("urb :%p", purb); @@ -108,10 +104,12 @@ pbuff_t b; dbg("dabusb_cancel_queue"); + spin_lock_irqsave (&s->lock, flags); for (p = q->next; p != q; p = p->next) { b = list_entry (p, buff_t, buff_list); + #ifdef DEBUG dump_urb(b->purb); #endif @@ -130,26 +128,34 @@ dbg("dabusb_free_queue"); for (p = q->next; p != q;) { b = list_entry (p, buff_t, buff_list); -#ifdef DEBUG + +#ifdef DEBUG dump_urb(b->purb); #endif if (b->purb->transfer_buffer) kfree (b->purb->transfer_buffer); - if (b->purb) - kfree (b->purb); + usb_free_urb(b->purb); tmp = p->next; list_del (p); kfree (b); p = tmp; } + return 0; } /*-------------------------------------------------------------------*/ static int dabusb_free_buffers (pdabusb_t s) { + unsigned long flags; dbg("dabusb_free_buffers"); + + spin_lock_irqsave(&s->lock, flags); + dabusb_free_queue (&s->free_buff_list); dabusb_free_queue (&s->rec_buff_list); + + spin_unlock_irqrestore(&s->lock, flags); + s->got_mem = 0; return 0; } @@ -163,14 +169,14 @@ int dst = 0; void *buf = purb->transfer_buffer; -#ifdef DEBUG_ALL dbg("dabusb_iso_complete"); -#endif - if (purb->status != USB_ST_URB_KILLED) { + + // process if URB was not killed + if (purb->status != -ENOENT) { unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE); int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)); for (i = 0; i < purb->number_of_packets; i++) - if (purb->iso_frame_desc[i].status == USB_ST_NOERROR) { + if (!purb->iso_frame_desc[i].status) { len = purb->iso_frame_desc[i].actual_length; if (len <= pipesize) { memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len); @@ -179,6 +185,8 @@ else err("dabusb_iso_complete: invalid len %d", len); } + else + warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status); if (dst != purb->actual_length) err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length); } @@ -199,10 +207,9 @@ int packets = _ISOPIPESIZE / pipesize; int transfer_buffer_length = packets * pipesize; int i; - int len = sizeof (urb_t) + packets * sizeof (iso_packet_descriptor_t); - dbg("dabusb_alloc_buffers len:%d pipesize:%d packets:%d transfer_buffer_len:%d", - len, pipesize, packets, transfer_buffer_length); + dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d", + pipesize, packets, transfer_buffer_length); while (buffers < (s->total_buffer_size << 10)) { b = (pbuff_t) kmalloc (sizeof (buff_t), GFP_KERNEL); @@ -212,13 +219,13 @@ } memset (b, sizeof (buff_t), 0); b->s = s; - b->purb = (purb_t) kmalloc (len, GFP_KERNEL); + b->purb = usb_alloc_urb(packets); if (!b->purb) { - err("kmalloc(sizeof(urb_t)+packets*sizeof(iso_packet_descriptor_t))==NULL"); + err("usb_alloc_urb == NULL"); kfree (b); goto err; } - memset (b->purb, 0, len); + b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL); if (!b->purb->transfer_buffer) { kfree (b->purb); @@ -247,124 +254,55 @@ return 0; -err: + err: dabusb_free_buffers (s); return -ENOMEM; } /*-------------------------------------------------------------------*/ -static int dabusb_reset_pipe (struct usb_device *usbdev, unsigned int ep) -{ - dbg("dabusb_reset_pipe"); - if ((ep & ~0x80) >= 16) - return -EINVAL; - - usb_settoggle (usbdev, ep & 0xf, !(ep & 0x80), 0); - - return 0; -} -/* --------------------------------------------------------------------- */ -static int dabusb_submit_urb (pdabusb_t s, purb_t purb) -{ - int ret; - bulk_completion_context_t context; - - init_waitqueue_head (&context.wait); - purb->context = &context; - -#ifdef DEBUG_ALL - dump_urb(purb); -#endif - - ret = usb_submit_urb (purb); - if (ret < 0) { - dbg("dabusb_bulk: usb_submit_urb returned %d", ret); - return -EINVAL; - } - interruptible_sleep_on_timeout (&context.wait, HZ); - if (purb->status == USB_ST_URB_PENDING) { - err("dabusb_usb_submit_urb: %p timed out", purb); - usb_unlink_urb (purb); - dabusb_reset_pipe(purb->dev, purb->pipe); - return -ETIMEDOUT; - } - return purb->status; -} -/* --------------------------------------------------------------------- */ -static void dabusb_bulk_complete (purb_t purb) -{ - pbulk_completion_context_t context = purb->context; - -#ifdef DEBUG_ALL - dbg("dabusb_bulk_complete"); - dump_urb(purb); -#endif - wake_up (&context->wait); -} - -/* --------------------------------------------------------------------- */ static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb) { int ret; - urb_t urb; unsigned int pipe; + int actual_length; -#ifdef DEBUG_ALL dbg("dabusb_bulk"); -#endif if (!pb->pipe) pipe = usb_rcvbulkpipe (s->usbdev, 2); else pipe = usb_sndbulkpipe (s->usbdev, 2); - memset (&urb, 0, sizeof (urb_t)); - FILL_BULK_URB ((&urb), s->usbdev, pipe, pb->data, pb->size, dabusb_bulk_complete, NULL); + ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 1000); + if(ret<0) { + err("dabusb: usb_bulk_msg failed(%d)",ret); + } + + if( ret == -EPIPE ) { + warn("CLEAR_FEATURE request to remove STALL condition."); + if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe))) + err("request failed"); + } - ret = dabusb_submit_urb (s, &urb); - pb->size = urb.actual_length; + pb->size = actual_length; return ret; } /* --------------------------------------------------------------------- */ static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len) { int ret; - urb_t urb; - unsigned int pipe; - unsigned char *setup = kmalloc (8, GFP_KERNEL); - unsigned char *transfer_buffer; + unsigned char *transfer_buffer = kmalloc (len, GFP_KERNEL); - if (!setup) { - err("dabusb_writemem: kmalloc(8) failed."); - return -ENOMEM; - } - transfer_buffer = kmalloc (len, GFP_KERNEL); if (!transfer_buffer) { err("dabusb_writemem: kmalloc(%d) failed.", len); - kfree (setup); return -ENOMEM; } - setup[0] = 0x40; - setup[1] = 0xa0; - setup[2] = pos & 0xff; - setup[3] = pos >> 8; - setup[4] = 0; - setup[5] = 0; - setup[6] = len & 0xff; - setup[7] = len >> 8; memcpy (transfer_buffer, data, len); - pipe = usb_sndctrlpipe (s->usbdev, 0); + ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300); - memset (&urb, 0, sizeof (urb_t)); - FILL_CONTROL_URB ((&urb), s->usbdev, pipe, setup, transfer_buffer, len, dabusb_bulk_complete, NULL); - - ret = dabusb_submit_urb (s, &urb); - kfree (setup); kfree (transfer_buffer); - if (ret < 0) - return ret; - return urb.status; + return ret; } /* --------------------------------------------------------------------- */ static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit) @@ -379,21 +317,23 @@ PINTEL_HEX_RECORD ptr = firmware; dbg("Enter dabusb_loadmem (internal)"); - + ret = dabusb_8051_reset (s, 1); while (ptr->Type == 0) { -#ifdef DEBUG_ALL - err("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length); -#endif + + dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length); + ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length); if (ret < 0) { - err("dabusb_writemem failed (%04X %p %d)", ptr->Address, ptr->Data, ptr->Length); + err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length); break; } ptr++; } ret = dabusb_8051_reset (s, 0); + dbg("dabusb_loadmem: exit"); + return ret; } /* --------------------------------------------------------------------- */ @@ -406,6 +346,7 @@ b->data[3] = 0; dbg("dabusb_fpga_clear"); + return dabusb_bulk (s, b); } /* --------------------------------------------------------------------- */ @@ -418,6 +359,7 @@ b->data[3] = 0; dbg("dabusb_fpga_init"); + return dabusb_bulk (s, b); } /* --------------------------------------------------------------------- */ @@ -429,6 +371,7 @@ unsigned char *buf = bitstream; dbg("Enter dabusb_fpga_download (internal)"); + if (!b) { err("kmalloc(sizeof(bulk_transfer_t))==NULL"); return -ENOMEM; @@ -438,7 +381,9 @@ ret = dabusb_fpga_clear (s, b); mdelay (10); blen = buf[73] + (buf[72] << 8); + dbg("Bitstream len: %i", blen); + b->data[0] = 0x2b; b->data[1] = 0; b->data[2] = 0; @@ -460,6 +405,7 @@ kfree (b); dbg("exit dabusb_fpga_download"); + return ret; } @@ -484,12 +430,12 @@ static int dabusb_startrek (pdabusb_t s) { if (!s->got_mem && s->state != _started) { + dbg("dabusb_startrek"); if (dabusb_alloc_buffers (s) < 0) return -ENOMEM; dabusb_stop (s); - dabusb_reset_pipe (s->usbdev, _DABUSB_ISOPIPE); s->state = _started; s->readptr = 0; } @@ -497,11 +443,11 @@ if (!list_empty (&s->free_buff_list)) { pbuff_t end; int ret; + + while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) { - while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) { -#ifdef DEBUG_ALL dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list); -#endif + end = list_entry (s->rec_buff_list.prev, buff_t, buff_list); ret = usb_submit_urb (end->purb); @@ -509,29 +455,28 @@ err("usb_submit_urb returned:%d", ret); if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) err("startrek: dabusb_add_buf_tail failed"); + break; } else atomic_inc (&s->pending_io); } -#ifdef DEBUG_ALL dbg("pending_io: %d",s->pending_io.counter); -#endif } + return 0; } static ssize_t dabusb_read (struct file *file, char *buf, size_t count, loff_t * ppos) { pdabusb_t s = (pdabusb_t) file->private_data; + unsigned long flags; unsigned ret = 0; int rem; int cnt; pbuff_t b; purb_t purb = NULL; -#ifdef DEBUG_ALL dbg("dabusb_read"); -#endif if (*ppos) return -ESPIPE; @@ -545,14 +490,23 @@ while (count > 0) { dabusb_startrek (s); + + spin_lock_irqsave (&s->lock, flags); + if (list_empty (&s->rec_buff_list)) { + + spin_unlock_irqrestore(&s->lock, flags); + err("error: rec_buf_list is empty"); goto err; } + b = list_entry (s->rec_buff_list.next, buff_t, buff_list); purb = b->purb; - if (purb->status == USB_ST_URB_PENDING) { + spin_unlock_irqrestore(&s->lock, flags); + + if (purb->status == -EINPROGRESS) { if (file->f_flags & O_NONBLOCK) // return nonblocking { if (!ret) @@ -567,10 +521,15 @@ ret = -ERESTARTSYS; goto err; } + + spin_lock_irqsave (&s->lock, flags); + if (list_empty (&s->rec_buff_list)) { + spin_unlock_irqrestore(&s->lock, flags); err("error: still no buffer available."); goto err; } + spin_unlock_irqrestore(&s->lock, flags); s->readptr = 0; } if (s->remove_pending) { @@ -585,9 +544,7 @@ else cnt = count; -#ifdef DEBUG_ALL dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt); -#endif if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) { err("read: copy_to_user failed"); @@ -608,7 +565,7 @@ s->readptr = 0; } } -err: //up(&s->mutex); + err: //up(&s->mutex); return ret; } @@ -641,14 +598,14 @@ } down (&s->mutex); } - s->opened = 1; - up (&s->mutex); - if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { - err("dabusb: set_interface failed"); + err("set_interface failed"); MOD_DEC_USE_COUNT; return -EINVAL; } + s->opened = 1; + up (&s->mutex); + file->f_pos = 0; file->private_data = s; @@ -668,7 +625,7 @@ if (!s->remove_pending) { if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) - err("dabusb: set_interface failed"); + err("set_interface failed"); } else wake_up (&s->remove_ok); @@ -684,9 +641,8 @@ pbulk_transfer_t pbulk; int ret = 0; int version = DABUSB_VERSION; - DECLARE_WAITQUEUE (wait, current); -// dbg("dabusb_ioctl"); + dbg("dabusb_ioctl"); if (s->remove_pending) return -EIO; @@ -737,19 +693,11 @@ static struct file_operations dabusb_fops = { - dabusb_llseek, - dabusb_read, - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - dabusb_ioctl, - NULL, /* mmap */ - dabusb_open, - NULL, /* flush */ - dabusb_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL /* lock */ + llseek: dabusb_llseek, + read: dabusb_read, + ioctl: dabusb_ioctl, + open: dabusb_open, + release: dabusb_release, }; static int dabusb_find_struct (void) @@ -799,8 +747,10 @@ err("set_configuration failed"); goto reject; } - if (usbdev->descriptor.idProduct == 0x2131) + if (usbdev->descriptor.idProduct == 0x2131) { dabusb_loadmem (s, NULL); + goto reject; + } else { dabusb_fpga_download (s, NULL); @@ -814,7 +764,7 @@ MOD_INC_USE_COUNT; return s; -reject: + reject: up (&s->mutex); s->usbdev = NULL; return NULL; @@ -869,12 +819,14 @@ usb_register (&dabusb_driver); dbg("dabusb_init: driver registered"); + return 0; } void __exit dabusb_cleanup (void) { dbg("dabusb_cleanup"); + usb_deregister (&dabusb_driver); } diff -u --recursive --new-file v2.3.42/linux/drivers/usb/dabusb.h linux/drivers/usb/dabusb.h --- v2.3.42/linux/drivers/usb/dabusb.h Fri Jan 7 19:13:22 2000 +++ linux/drivers/usb/dabusb.h Mon Feb 7 19:12:12 2000 @@ -33,7 +33,6 @@ int opened; struct list_head free_buff_list; struct list_head rec_buff_list; - int in_use; } dabusb_t,*pdabusb_t; typedef struct diff -u --recursive --new-file v2.3.42/linux/drivers/usb/devices.c linux/drivers/usb/devices.c --- v2.3.42/linux/drivers/usb/devices.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/devices.c Wed Feb 9 11:51:13 2000 @@ -366,7 +366,7 @@ /*****************************************************************/ static char *usb_device_dump(char *start, char *end, struct usb_device *usbdev, - int bus, int level, int index, int count) + struct usb_bus *bus, int level, int index, int count) { int chix; int cnt = 0; @@ -380,7 +380,7 @@ * So the root hub's parent is 0 and any device that is * plugged into the root hub has a parent of 0. */ - start += sprintf(start, format_topo, bus, level, parent_devnum, index, count, + start += sprintf(start, format_topo, bus->busnum, level, parent_devnum, index, count, usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild); /* * level = topology-tier level; @@ -388,9 +388,13 @@ * index = parent's connector number; * count = device count at this level */ - /* do not dump descriptors for root hub */ - if (usbdev->devnum >= 0) - start = usb_dump_desc(start, end, usbdev); + /* If this is the root hub, display the bandwidth information */ + if (level == 0) + start += sprintf(start, format_bandwidth, bus->bandwidth_allocated, + FRAME_TIME_MAX_USECS_ALLOC, + (100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC, + bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs); + start = usb_dump_desc(start, end, usbdev); if (start > end) return start + sprintf(start, "(truncated)\n"); /* Now look at all of this device's children. */ @@ -422,12 +426,9 @@ pos = *ppos; /* enumerate busses */ for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { - /* print bandwidth allocation */ + /* print devices for this bus */ bus = list_entry(buslist, struct usb_bus, bus_list); - len = sprintf(page, format_bandwidth, bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC, - (100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC, - bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs); - end = usb_device_dump(page + len, page + (2*PAGE_SIZE - 256), bus->root_hub, bus->busnum, 0, 0, 0); + end = usb_device_dump(page, page + (2*PAGE_SIZE - 256), bus->root_hub, bus, 0, 0, 0); len = end - page; if (len > pos) { len -= pos; @@ -512,15 +513,9 @@ } struct file_operations usbdevfs_devices_fops = { - usb_device_lseek, /* lseek */ - usb_device_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - usb_device_poll, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - usb_device_open, /* open */ - NULL, /* flush */ - usb_device_release, /* release */ - NULL /* fsync */ + llseek: usb_device_lseek, + read: usb_device_read, + poll: usb_device_poll, + open: usb_device_open, + release: usb_device_release, }; diff -u --recursive --new-file v2.3.42/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.3.42/linux/drivers/usb/devio.c Fri Jan 21 18:19:17 2000 +++ linux/drivers/usb/devio.c Wed Feb 9 11:42:35 2000 @@ -19,7 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: devio.c,v 1.6 2000/01/11 23:26:33 tom Exp $ + * $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $ * * This file implements the usbdevfs/x/y files, where * x is the bus number and y the device number. @@ -132,8 +132,8 @@ urb->transfer_buffer = data; urb->transfer_buffer_length = size; ret = do_sync(urb, timeout); - if (ret >= 0) - ret = urb->status; + //if (ret >= 0) + // ret = urb->status; if (ret >= 0) ret = urb->actual_length; kfree(urb->setup_packet); @@ -154,8 +154,8 @@ urb->transfer_buffer = data; urb->transfer_buffer_length = len; ret = do_sync(urb, timeout); - if (ret >= 0) - ret = urb->status; + //if (ret >= 0) + // ret = urb->status; if (ret >= 0 && actual_length != NULL) *actual_length = urb->actual_length; usb_free_urb(urb); @@ -321,7 +321,7 @@ struct dev_state *ps = as->ps; struct siginfo sinfo; -#if 0 +#if 1 printk(KERN_DEBUG "usbdevfs: async_completed: status %d errcount %d actlen %d pipe 0x%x\n", urb->status, urb->error_count, urb->actual_length, urb->pipe); #endif @@ -345,7 +345,7 @@ unsigned long flags; spin_lock_irqsave(&ps->lock, flags); - if (!list_empty(&ps->async_pending)) { + while (!list_empty(&ps->async_pending)) { as = list_entry(ps->async_pending.next, struct async, asynclist); list_del(&as->asynclist); INIT_LIST_HEAD(&as->asynclist); @@ -1003,17 +1003,12 @@ } static struct file_operations usbdevfs_device_file_operations = { - usbdev_lseek, /* lseek */ - usbdev_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - usbdev_poll, /* poll */ - usbdev_ioctl, /* ioctl */ - NULL, /* mmap */ - usbdev_open, /* open */ - NULL, /* flush */ - usbdev_release, /* release */ - NULL /* fsync */ + llseek: usbdev_lseek, + read: usbdev_read, + poll: usbdev_poll, + ioctl: usbdev_ioctl, + open: usbdev_open, + release: usbdev_release, }; struct inode_operations usbdevfs_device_inode_operations = { diff -u --recursive --new-file v2.3.42/linux/drivers/usb/drivers.c linux/drivers/usb/drivers.c --- v2.3.42/linux/drivers/usb/drivers.c Fri Jan 21 18:19:17 2000 +++ linux/drivers/usb/drivers.c Wed Feb 9 11:42:35 2000 @@ -112,15 +112,6 @@ } struct file_operations usbdevfs_drivers_fops = { - usb_driver_lseek, /* lseek */ - usb_driver_read, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* open */ - NULL, /* flush */ - NULL, /* release */ - NULL /* fsync */ + llseek: usb_driver_lseek, + read: usb_driver_read, }; diff -u --recursive --new-file v2.3.42/linux/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.3.42/linux/drivers/usb/hid.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/hid.c Mon Feb 7 19:14:45 2000 @@ -53,6 +53,8 @@ #define hid_dump_device(c) do { } while (0) #endif +#define unk KEY_UNKNOWN + static unsigned char hid_keyboard[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, @@ -61,13 +63,13 @@ 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95, - 120,121,122,123,192,138,192,192,128,129,131,137,133,135,136,113, - 115,114,192,192,192,192,192,124,192,192,192,192,192,192,192,192, - 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, - 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, - 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, - 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, - 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, + 120,121,122,123,unk,138,unk,unk,128,129,131,137,133,135,136,113, + 115,114,unk,unk,unk,unk,unk,124,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + 134,130,132,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, 29, 42, 56,125, 97, 54,100,126 }; diff -u --recursive --new-file v2.3.42/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.3.42/linux/drivers/usb/hub.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/hub.c Mon Feb 7 19:12:16 2000 @@ -446,8 +446,18 @@ } if (portchange & USB_PORT_STAT_C_ENABLE) { - dbg("port %d enable change", i + 1); + dbg("port %d enable change, status %x", i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); + + // EM interference sometimes causes bad shielded USB devices to + // be shutdown by the hub, this hack enables them again. + // Works at least with mouse driver. + if (!(portstatus & USB_PORT_STAT_ENABLE) && + (portstatus & USB_PORT_STAT_CONNECTION)) { + err("already running port %i disabled by hub (EMI?), re-enabling...", + i + 1); + usb_hub_port_connect_change(dev, i); + } } if (portstatus & USB_PORT_STAT_SUSPEND) { diff -u --recursive --new-file v2.3.42/linux/drivers/usb/ibmcam.c linux/drivers/usb/ibmcam.c --- v2.3.42/linux/drivers/usb/ibmcam.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/ibmcam.c Mon Feb 7 19:15:56 2000 @@ -26,6 +26,21 @@ #include "usb.h" #include "ibmcam.h" +/* + * IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED: This symbol controls + * the locking of the driver. If non-zero, the driver counts the + * probe() call as usage and increments module usage counter; this + * effectively prevents removal of the module (with rmmod) until the + * device is unplugged (then disconnect() callback reduces the module + * usage counter back, and module can be removed). + * + * This behavior may be useful if you prefer to lock the driver in + * memory until device is unplugged. However you can't reload the + * driver if you want to alter some parameters - you'd need to unplug + * the camera first. Therefore, I recommend setting 0. + */ +#define IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED 0 + #define ENABLE_HEXDUMP 0 /* Enable if you need it */ static int debug = 0; @@ -100,6 +115,7 @@ static int init_contrast = 192; static int init_color = 128; static int init_hue = 128; +static int hue_correction = 128; MODULE_PARM(debug, "i"); MODULE_PARM(flags, "i"); @@ -111,6 +127,7 @@ MODULE_PARM(init_contrast, "i"); MODULE_PARM(init_color, "i"); MODULE_PARM(init_hue, "i"); +MODULE_PARM(hue_correction, "i"); MODULE_AUTHOR ("module author"); MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000"); @@ -123,6 +140,10 @@ static const unsigned short light_27 = 0x0027; static const unsigned short sharp_13 = 0x0013; +#define MAX_IBMCAM 4 + +struct usb_ibmcam cams[MAX_IBMCAM]; + /*******************************/ /* Memory management functions */ /*******************************/ @@ -130,6 +151,7 @@ #define MDEBUG(x) do { } while(0) /* Debug memory management */ static struct usb_driver ibmcam_driver; +static void usb_ibmcam_release(struct usb_ibmcam *ibmcam); /* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. @@ -555,12 +577,14 @@ struct ibmcam_frame *frame; unsigned char *data, *f, *chromaLine; unsigned int len; - const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL; /* V4L line offset */ - int y, u, v, i, frame_done=0, mono_plane, hue_corr, color_corr; - - hue_corr = (ibmcam->vpic.hue - 0x8000) >> 10; /* -32..+31 */ - color_corr = (ibmcam->vpic.colour - 0x8000) >> 10; /* -32..+31 */ + const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL; /* V4L line offset */ + const int hue_corr = (ibmcam->vpic.hue - 0x8000) >> 10; /* -32..+31 */ + const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */ + const int ccm = 128; /* Color correction median - see below */ + int y, u, v, i, frame_done=0, mono_plane, color_corr; + color_corr = (ibmcam->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ + RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1); data = ibmcam->scratch; frame = &ibmcam->frame[ibmcam->curframe]; @@ -694,11 +718,18 @@ else { if (frame->order_uv) { u = chromaLine[(i >> 1) << 2] + hue_corr; - v = chromaLine[((i >> 1) << 2) + 2] + color_corr; + v = chromaLine[((i >> 1) << 2) + 2] + hue2_corr; } else { - v = chromaLine[(i >> 1) << 2] + color_corr; + v = chromaLine[(i >> 1) << 2] + hue2_corr; u = chromaLine[((i >> 1) << 2) + 2] + hue_corr; } + + /* Apply color correction */ + if (color_corr != 0) { + /* Magnify up to 2 times, reduce down to zero saturation */ + u = 128 + ((ccm + color_corr) * (u - 128)) / ccm; + v = 128 + ((ccm + color_corr) * (v - 128)) / ccm; + } YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv); } @@ -915,7 +946,7 @@ int i; /* We don't want to do anything if we are about to be removed! */ - if (ibmcam->remove_pending) + if (!IBMCAM_IS_OPERATIONAL(ibmcam)) return; #if 0 @@ -976,38 +1007,46 @@ return; } +/* + * usb_ibmcam_veio() + * + * History: + * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged. + */ static int usb_ibmcam_veio( - struct usb_device *dev, + struct usb_ibmcam *ibmcam, unsigned char req, unsigned short value, unsigned short index) { static const char proc[] = "usb_ibmcam_veio"; - unsigned char cp[8] = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef }; - const unsigned short len = sizeof(cp); + unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */; int i; + if (!IBMCAM_IS_OPERATIONAL(ibmcam)) + return 0; + if (req == 1) { i = usb_control_msg( - dev, - usb_rcvctrlpipe(dev, 0), + ibmcam->dev, + usb_rcvctrlpipe(ibmcam->dev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, value, index, cp, - len, + sizeof(cp), HZ); #if 0 printk(KERN_DEBUG "USB => %02x%02x%02x%02x%02x%02x%02x%02x " - "(req=$%02x val=$%04x ind=$%04x len=%d.)\n", + "(req=$%02x val=$%04x ind=$%04x)\n", cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7], - req, value, index, len); + req, value, index); #endif } else { i = usb_control_msg( - dev, - usb_sndctrlpipe(dev, 0), + ibmcam->dev, + usb_sndctrlpipe(ibmcam->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, value, @@ -1016,8 +1055,11 @@ 0, HZ); } - if (i < 0) - printk(KERN_ERR "%s: ERROR=%d.\n", proc, i); + if (i < 0) { + printk(KERN_ERR "%s: ERROR=%d. Camera stopped - " + "reconnect or reload driver.\n", proc, i); + ibmcam->last_error = i; + } return i; } @@ -1053,86 +1095,86 @@ * History: * 1/2/00 Created. */ -static void usb_ibmcam_send_FF_04_02(struct usb_device *dev) +static void usb_ibmcam_send_FF_04_02(struct usb_ibmcam *ibmcam) { - usb_ibmcam_veio(dev, 0, 0x00FF, 0x0127); - usb_ibmcam_veio(dev, 0, 0x0004, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0002, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x00FF, 0x0127); + usb_ibmcam_veio(ibmcam, 0, 0x0004, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124); } -static void usb_ibmcam_send_00_04_06(struct usb_device *dev) +static void usb_ibmcam_send_00_04_06(struct usb_ibmcam *ibmcam) { - usb_ibmcam_veio(dev, 0, 0x0000, 0x0127); - usb_ibmcam_veio(dev, 0, 0x0004, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0006, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0127); + usb_ibmcam_veio(ibmcam, 0, 0x0004, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0006, 0x0124); } -static void usb_ibmcam_send_x_00(struct usb_device *dev, unsigned short x) +static void usb_ibmcam_send_x_00(struct usb_ibmcam *ibmcam, unsigned short x) { - usb_ibmcam_veio(dev, 0, x, 0x0127); - usb_ibmcam_veio(dev, 0, 0x0000, 0x0124); + usb_ibmcam_veio(ibmcam, 0, x, 0x0127); + usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); } -static void usb_ibmcam_send_x_00_05(struct usb_device *dev, unsigned short x) +static void usb_ibmcam_send_x_00_05(struct usb_ibmcam *ibmcam, unsigned short x) { - usb_ibmcam_send_x_00(dev, x); - usb_ibmcam_veio(dev, 0, 0x0005, 0x0124); + usb_ibmcam_send_x_00(ibmcam, x); + usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); } -static void usb_ibmcam_send_x_00_05_02(struct usb_device *dev, unsigned short x) +static void usb_ibmcam_send_x_00_05_02(struct usb_ibmcam *ibmcam, unsigned short x) { - usb_ibmcam_veio(dev, 0, x, 0x0127); - usb_ibmcam_veio(dev, 0, 0x0000, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0005, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0002, 0x0124); + usb_ibmcam_veio(ibmcam, 0, x, 0x0127); + usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124); } -static void usb_ibmcam_send_x_01_00_05(struct usb_device *dev, unsigned short x) +static void usb_ibmcam_send_x_01_00_05(struct usb_ibmcam *ibmcam, unsigned short x) { - usb_ibmcam_veio(dev, 0, x, 0x0127); - usb_ibmcam_veio(dev, 0, 0x0001, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0000, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0005, 0x0124); + usb_ibmcam_veio(ibmcam, 0, x, 0x0127); + usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); } -static void usb_ibmcam_send_x_00_05_02_01(struct usb_device *dev, unsigned short x) +static void usb_ibmcam_send_x_00_05_02_01(struct usb_ibmcam *ibmcam, unsigned short x) { - usb_ibmcam_veio(dev, 0, x, 0x0127); - usb_ibmcam_veio(dev, 0, 0x0000, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0005, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0002, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0001, 0x0124); + usb_ibmcam_veio(ibmcam, 0, x, 0x0127); + usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124); } -static void usb_ibmcam_send_x_00_05_02_08_01(struct usb_device *dev, unsigned short x) +static void usb_ibmcam_send_x_00_05_02_08_01(struct usb_ibmcam *ibmcam, unsigned short x) { - usb_ibmcam_veio(dev, 0, x, 0x0127); - usb_ibmcam_veio(dev, 0, 0x0000, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0005, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0002, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0008, 0x0124); - usb_ibmcam_veio(dev, 0, 0x0001, 0x0124); + usb_ibmcam_veio(ibmcam, 0, x, 0x0127); + usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0008, 0x0124); + usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124); } -static void usb_ibmcam_Packet_Format1(struct usb_device *dev, unsigned char fkey, unsigned char val) +static void usb_ibmcam_Packet_Format1(struct usb_ibmcam *ibmcam, unsigned char fkey, unsigned char val) { - usb_ibmcam_send_x_01_00_05 (dev, unknown_88); - usb_ibmcam_send_x_00_05 (dev, fkey); - usb_ibmcam_send_x_00_05_02_08_01(dev, val); - usb_ibmcam_send_x_00_05 (dev, unknown_88); - usb_ibmcam_send_x_00_05_02_01 (dev, fkey); - usb_ibmcam_send_x_00_05 (dev, unknown_89); - usb_ibmcam_send_x_00 (dev, fkey); - usb_ibmcam_send_00_04_06 (dev); - usb_ibmcam_veio (dev, 1, 0x0000, 0x0126); - usb_ibmcam_send_FF_04_02 (dev); + usb_ibmcam_send_x_01_00_05 (ibmcam, unknown_88); + usb_ibmcam_send_x_00_05 (ibmcam, fkey); + usb_ibmcam_send_x_00_05_02_08_01(ibmcam, val); + usb_ibmcam_send_x_00_05 (ibmcam, unknown_88); + usb_ibmcam_send_x_00_05_02_01 (ibmcam, fkey); + usb_ibmcam_send_x_00_05 (ibmcam, unknown_89); + usb_ibmcam_send_x_00 (ibmcam, fkey); + usb_ibmcam_send_00_04_06 (ibmcam); + usb_ibmcam_veio (ibmcam, 1, 0x0000, 0x0126); + usb_ibmcam_send_FF_04_02 (ibmcam); } -static void usb_ibmcam_PacketFormat2(struct usb_device *dev, unsigned char fkey, unsigned char val) +static void usb_ibmcam_PacketFormat2(struct usb_ibmcam *ibmcam, unsigned char fkey, unsigned char val) { - usb_ibmcam_send_x_01_00_05 (dev, unknown_88); - usb_ibmcam_send_x_00_05 (dev, fkey); - usb_ibmcam_send_x_00_05_02 (dev, val); + usb_ibmcam_send_x_01_00_05 (ibmcam, unknown_88); + usb_ibmcam_send_x_00_05 (ibmcam, fkey); + usb_ibmcam_send_x_00_05_02 (ibmcam, val); } /* @@ -1149,7 +1191,6 @@ */ static void usb_ibmcam_adjust_contrast(struct usb_ibmcam *ibmcam) { - struct usb_device *dev = ibmcam->dev; unsigned char new_contrast = ibmcam->vpic.contrast >> 12; const int ntries = 5; @@ -1160,10 +1201,9 @@ int i; ibmcam->vpic_old.contrast = new_contrast; for (i=0; i < ntries; i++) { - usb_ibmcam_Packet_Format1(dev, contrast_14, new_contrast); - usb_ibmcam_send_FF_04_02(dev); + usb_ibmcam_Packet_Format1(ibmcam, contrast_14, new_contrast); + usb_ibmcam_send_FF_04_02(ibmcam); } - /*usb_ibmcam_veio(dev, 0, 0x00FF, 0x0127);*/ } } @@ -1179,7 +1219,6 @@ static void usb_ibmcam_change_lighting_conditions(struct usb_ibmcam *ibmcam) { static const char proc[] = "usb_ibmcam_change_lighting_conditions"; - struct usb_device *dev = ibmcam->dev; const int ntries = 5; int i; @@ -1188,13 +1227,12 @@ printk(KERN_INFO "%s: Set lighting to %hu.\n", proc, lighting); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, light_27, (unsigned short) lighting); + usb_ibmcam_Packet_Format1(ibmcam, light_27, (unsigned short) lighting); } static void usb_ibmcam_set_sharpness(struct usb_ibmcam *ibmcam) { static const char proc[] = "usb_ibmcam_set_sharpness"; - struct usb_device *dev = ibmcam->dev; static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a }; unsigned short i, sv; @@ -1204,16 +1242,15 @@ sv = sa[sharpness - SHARPNESS_MIN]; for (i=0; i < 2; i++) { - usb_ibmcam_send_x_01_00_05 (dev, unknown_88); - usb_ibmcam_send_x_00_05 (dev, sharp_13); - usb_ibmcam_send_x_00_05_02 (dev, sv); + usb_ibmcam_send_x_01_00_05 (ibmcam, unknown_88); + usb_ibmcam_send_x_00_05 (ibmcam, sharp_13); + usb_ibmcam_send_x_00_05_02 (ibmcam, sv); } } static void usb_ibmcam_set_brightness(struct usb_ibmcam *ibmcam) { static const char proc[] = "usb_ibmcam_set_brightness"; - struct usb_device *dev = ibmcam->dev; static const unsigned short n = 1; unsigned short i, j, bv[3]; @@ -1228,7 +1265,7 @@ for (j=0; j < 3; j++) for (i=0; i < n; i++) - usb_ibmcam_Packet_Format1(dev, bright_3x[j], bv[j]); + usb_ibmcam_Packet_Format1(ibmcam, bright_3x[j], bv[j]); } static void usb_ibmcam_adjust_picture(struct usb_ibmcam *ibmcam) @@ -1239,197 +1276,196 @@ static int usb_ibmcam_setup(struct usb_ibmcam *ibmcam) { - struct usb_device *dev = ibmcam->dev; const int ntries = 5; int i; - usb_ibmcam_veio(dev, 1, 0, 0x128); - usb_ibmcam_veio(dev, 1, 0x00, 0x0100); - usb_ibmcam_veio(dev, 0, 0x01, 0x0100); /* LED On */ - usb_ibmcam_veio(dev, 1, 0x00, 0x0100); - usb_ibmcam_veio(dev, 0, 0x81, 0x0100); /* LED Off */ - usb_ibmcam_veio(dev, 1, 0x00, 0x0100); - usb_ibmcam_veio(dev, 0, 0x01, 0x0100); /* LED On */ - usb_ibmcam_veio(dev, 0, 0x01, 0x0108); - - usb_ibmcam_veio(dev, 0, 0x03, 0x0112); - usb_ibmcam_veio(dev, 1, 0x00, 0x0115); - usb_ibmcam_veio(dev, 0, 0x06, 0x0115); - usb_ibmcam_veio(dev, 1, 0x00, 0x0116); - usb_ibmcam_veio(dev, 0, 0x44, 0x0116); - usb_ibmcam_veio(dev, 1, 0x00, 0x0116); - usb_ibmcam_veio(dev, 0, 0x40, 0x0116); - usb_ibmcam_veio(dev, 1, 0x00, 0x0115); - usb_ibmcam_veio(dev, 0, 0x0e, 0x0115); - usb_ibmcam_veio(dev, 0, 0x19, 0x012c); - - usb_ibmcam_Packet_Format1(dev, 0x00, 0x1e); - usb_ibmcam_Packet_Format1(dev, 0x39, 0x0d); - usb_ibmcam_Packet_Format1(dev, 0x39, 0x09); - usb_ibmcam_Packet_Format1(dev, 0x3b, 0x00); - usb_ibmcam_Packet_Format1(dev, 0x28, 0x22); - usb_ibmcam_Packet_Format1(dev, light_27, 0); - usb_ibmcam_Packet_Format1(dev, 0x2b, 0x1f); - usb_ibmcam_Packet_Format1(dev, 0x39, 0x08); + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0128); + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100); + usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100); /* LED On */ + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100); + usb_ibmcam_veio(ibmcam, 0, 0x81, 0x0100); /* LED Off */ + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100); + usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100); /* LED On */ + usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0108); + + usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0112); + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0115); + usb_ibmcam_veio(ibmcam, 0, 0x06, 0x0115); + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0116); + usb_ibmcam_veio(ibmcam, 0, 0x44, 0x0116); + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0116); + usb_ibmcam_veio(ibmcam, 0, 0x40, 0x0116); + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0115); + usb_ibmcam_veio(ibmcam, 0, 0x0e, 0x0115); + usb_ibmcam_veio(ibmcam, 0, 0x19, 0x012c); + + usb_ibmcam_Packet_Format1(ibmcam, 0x00, 0x1e); + usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x0d); + usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x09); + usb_ibmcam_Packet_Format1(ibmcam, 0x3b, 0x00); + usb_ibmcam_Packet_Format1(ibmcam, 0x28, 0x22); + usb_ibmcam_Packet_Format1(ibmcam, light_27, 0); + usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1f); + usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x08); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x2c, 0x00); + usb_ibmcam_Packet_Format1(ibmcam, 0x2c, 0x00); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x30, 0x14); + usb_ibmcam_Packet_Format1(ibmcam, 0x30, 0x14); - usb_ibmcam_PacketFormat2(dev, 0x39, 0x02); - usb_ibmcam_PacketFormat2(dev, 0x01, 0xe1); - usb_ibmcam_PacketFormat2(dev, 0x02, 0xcd); - usb_ibmcam_PacketFormat2(dev, 0x03, 0xcd); - usb_ibmcam_PacketFormat2(dev, 0x04, 0xfa); - usb_ibmcam_PacketFormat2(dev, 0x3f, 0xff); - usb_ibmcam_PacketFormat2(dev, 0x39, 0x00); - - usb_ibmcam_PacketFormat2(dev, 0x39, 0x02); - usb_ibmcam_PacketFormat2(dev, 0x0a, 0x37); - usb_ibmcam_PacketFormat2(dev, 0x0b, 0xb8); - usb_ibmcam_PacketFormat2(dev, 0x0c, 0xf3); - usb_ibmcam_PacketFormat2(dev, 0x0d, 0xe3); - usb_ibmcam_PacketFormat2(dev, 0x0e, 0x0d); - usb_ibmcam_PacketFormat2(dev, 0x0f, 0xf2); - usb_ibmcam_PacketFormat2(dev, 0x10, 0xd5); - usb_ibmcam_PacketFormat2(dev, 0x11, 0xba); - usb_ibmcam_PacketFormat2(dev, 0x12, 0x53); - usb_ibmcam_PacketFormat2(dev, 0x3f, 0xff); - usb_ibmcam_PacketFormat2(dev, 0x39, 0x00); - - usb_ibmcam_PacketFormat2(dev, 0x39, 0x02); - usb_ibmcam_PacketFormat2(dev, 0x16, 0x00); - usb_ibmcam_PacketFormat2(dev, 0x17, 0x28); - usb_ibmcam_PacketFormat2(dev, 0x18, 0x7d); - usb_ibmcam_PacketFormat2(dev, 0x19, 0xbe); - usb_ibmcam_PacketFormat2(dev, 0x3f, 0xff); - usb_ibmcam_PacketFormat2(dev, 0x39, 0x00); + usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02); + usb_ibmcam_PacketFormat2(ibmcam, 0x01, 0xe1); + usb_ibmcam_PacketFormat2(ibmcam, 0x02, 0xcd); + usb_ibmcam_PacketFormat2(ibmcam, 0x03, 0xcd); + usb_ibmcam_PacketFormat2(ibmcam, 0x04, 0xfa); + usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff); + usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00); + + usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02); + usb_ibmcam_PacketFormat2(ibmcam, 0x0a, 0x37); + usb_ibmcam_PacketFormat2(ibmcam, 0x0b, 0xb8); + usb_ibmcam_PacketFormat2(ibmcam, 0x0c, 0xf3); + usb_ibmcam_PacketFormat2(ibmcam, 0x0d, 0xe3); + usb_ibmcam_PacketFormat2(ibmcam, 0x0e, 0x0d); + usb_ibmcam_PacketFormat2(ibmcam, 0x0f, 0xf2); + usb_ibmcam_PacketFormat2(ibmcam, 0x10, 0xd5); + usb_ibmcam_PacketFormat2(ibmcam, 0x11, 0xba); + usb_ibmcam_PacketFormat2(ibmcam, 0x12, 0x53); + usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff); + usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00); + + usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02); + usb_ibmcam_PacketFormat2(ibmcam, 0x16, 0x00); + usb_ibmcam_PacketFormat2(ibmcam, 0x17, 0x28); + usb_ibmcam_PacketFormat2(ibmcam, 0x18, 0x7d); + usb_ibmcam_PacketFormat2(ibmcam, 0x19, 0xbe); + usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff); + usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x00, 0x18); + usb_ibmcam_Packet_Format1(ibmcam, 0x00, 0x18); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x13, 0x18); + usb_ibmcam_Packet_Format1(ibmcam, 0x13, 0x18); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x14, 0x06); + usb_ibmcam_Packet_Format1(ibmcam, 0x14, 0x06); /* This is default brightness */ for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x31, 0x37); + usb_ibmcam_Packet_Format1(ibmcam, 0x31, 0x37); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x32, 0x46); + usb_ibmcam_Packet_Format1(ibmcam, 0x32, 0x46); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x33, 0x55); + usb_ibmcam_Packet_Format1(ibmcam, 0x33, 0x55); - usb_ibmcam_Packet_Format1(dev, 0x2e, 0x04); + usb_ibmcam_Packet_Format1(ibmcam, 0x2e, 0x04); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x2d, 0x04); + usb_ibmcam_Packet_Format1(ibmcam, 0x2d, 0x04); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x29, 0x80); - usb_ibmcam_Packet_Format1(dev, 0x2c, 0x01); - usb_ibmcam_Packet_Format1(dev, 0x30, 0x17); - usb_ibmcam_Packet_Format1(dev, 0x39, 0x08); + usb_ibmcam_Packet_Format1(ibmcam, 0x29, 0x80); + usb_ibmcam_Packet_Format1(ibmcam, 0x2c, 0x01); + usb_ibmcam_Packet_Format1(ibmcam, 0x30, 0x17); + usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x08); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x34, 0x00); + usb_ibmcam_Packet_Format1(ibmcam, 0x34, 0x00); - usb_ibmcam_veio(dev, 0, 0x00, 0x0101); - usb_ibmcam_veio(dev, 0, 0x00, 0x010a); + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0101); + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010a); switch (videosize) { case VIDEOSIZE_128x96: - usb_ibmcam_veio(dev, 0, 0x80, 0x0103); - usb_ibmcam_veio(dev, 0, 0x60, 0x0105); - usb_ibmcam_veio(dev, 0, 0x0c, 0x010b); - usb_ibmcam_veio(dev, 0, 0x04, 0x011b); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x0b, 0x011d); - usb_ibmcam_veio(dev, 0, 0x00, 0x011e); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x00, 0x0129); + usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0103); + usb_ibmcam_veio(ibmcam, 0, 0x60, 0x0105); + usb_ibmcam_veio(ibmcam, 0, 0x0c, 0x010b); + usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x0b, 0x011d); + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0129); break; case VIDEOSIZE_176x144: - usb_ibmcam_veio(dev, 0, 0xb0, 0x0103); - usb_ibmcam_veio(dev, 0, 0x8f, 0x0105); - usb_ibmcam_veio(dev, 0, 0x06, 0x010b); - usb_ibmcam_veio(dev, 0, 0x04, 0x011b); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x0d, 0x011d); - usb_ibmcam_veio(dev, 0, 0x00, 0x011e); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x03, 0x0129); + usb_ibmcam_veio(ibmcam, 0, 0xb0, 0x0103); + usb_ibmcam_veio(ibmcam, 0, 0x8f, 0x0105); + usb_ibmcam_veio(ibmcam, 0, 0x06, 0x010b); + usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x0d, 0x011d); + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0129); break; case VIDEOSIZE_352x288: - usb_ibmcam_veio(dev, 0, 0xb0, 0x0103); - usb_ibmcam_veio(dev, 0, 0x90, 0x0105); - usb_ibmcam_veio(dev, 0, 0x02, 0x010b); - usb_ibmcam_veio(dev, 0, 0x04, 0x011b); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x05, 0x011d); - usb_ibmcam_veio(dev, 0, 0x00, 0x011e); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x00, 0x0129); + usb_ibmcam_veio(ibmcam, 0, 0xb0, 0x0103); + usb_ibmcam_veio(ibmcam, 0, 0x90, 0x0105); + usb_ibmcam_veio(ibmcam, 0, 0x02, 0x010b); + usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x05, 0x011d); + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0129); break; } - usb_ibmcam_veio(dev, 0, 0xff, 0x012b); + usb_ibmcam_veio(ibmcam, 0, 0xff, 0x012b); /* This is another brightness - don't know why */ for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x31, 0xc3); + usb_ibmcam_Packet_Format1(ibmcam, 0x31, 0xc3); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x32, 0xd2); + usb_ibmcam_Packet_Format1(ibmcam, 0x32, 0xd2); for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, 0x33, 0xe1); + usb_ibmcam_Packet_Format1(ibmcam, 0x33, 0xe1); /* Default contrast */ for (i=0; i < ntries; i++) - usb_ibmcam_Packet_Format1(dev, contrast_14, 0x0a); + usb_ibmcam_Packet_Format1(ibmcam, contrast_14, 0x0a); /* Default sharpness */ for (i=0; i < 2; i++) - usb_ibmcam_PacketFormat2(dev, sharp_13, 0x1a); /* Level 4 FIXME */ + usb_ibmcam_PacketFormat2(ibmcam, sharp_13, 0x1a); /* Level 4 FIXME */ /* Default lighting conditions */ - usb_ibmcam_Packet_Format1(dev, light_27, lighting); /* 0=Bright 2=Low */ + usb_ibmcam_Packet_Format1(ibmcam, light_27, lighting); /* 0=Bright 2=Low */ /* Assorted init */ switch (videosize) { case VIDEOSIZE_128x96: - usb_ibmcam_Packet_Format1(dev, 0x2b, 0x1e); - usb_ibmcam_veio(dev, 0, 0xc9, 0x0119); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x80, 0x0109); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x36, 0x0102); - usb_ibmcam_veio(dev, 0, 0x1a, 0x0104); - usb_ibmcam_veio(dev, 0, 0x04, 0x011a); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x2b, 0x011c); - usb_ibmcam_veio(dev, 0, 0x23, 0x012a); /* Same everywhere */ + usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1e); + usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x36, 0x0102); + usb_ibmcam_veio(ibmcam, 0, 0x1a, 0x0104); + usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x2b, 0x011c); + usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a); /* Same everywhere */ #if 0 - usb_ibmcam_veio(dev, 0, 0x00, 0x0106); - usb_ibmcam_veio(dev, 0, 0x38, 0x0107); + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0106); + usb_ibmcam_veio(ibmcam, 0, 0x38, 0x0107); #else - usb_ibmcam_veio(dev, 0, 0x02, 0x0106); - usb_ibmcam_veio(dev, 0, 0x2a, 0x0107); + usb_ibmcam_veio(ibmcam, 0, 0x02, 0x0106); + usb_ibmcam_veio(ibmcam, 0, 0x2a, 0x0107); #endif break; case VIDEOSIZE_176x144: - usb_ibmcam_Packet_Format1(dev, 0x2b, 0x1e); - usb_ibmcam_veio(dev, 0, 0xc9, 0x0119); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x80, 0x0109); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x04, 0x0102); - usb_ibmcam_veio(dev, 0, 0x02, 0x0104); - usb_ibmcam_veio(dev, 0, 0x04, 0x011a); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x2b, 0x011c); - usb_ibmcam_veio(dev, 0, 0x23, 0x012a); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x01, 0x0106); - usb_ibmcam_veio(dev, 0, 0xca, 0x0107); + usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1e); + usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x04, 0x0102); + usb_ibmcam_veio(ibmcam, 0, 0x02, 0x0104); + usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x2b, 0x011c); + usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0106); + usb_ibmcam_veio(ibmcam, 0, 0xca, 0x0107); break; case VIDEOSIZE_352x288: - usb_ibmcam_Packet_Format1(dev, 0x2b, 0x1f); - usb_ibmcam_veio(dev, 0, 0xc9, 0x0119); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x80, 0x0109); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x08, 0x0102); - usb_ibmcam_veio(dev, 0, 0x01, 0x0104); - usb_ibmcam_veio(dev, 0, 0x04, 0x011a); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x2f, 0x011c); - usb_ibmcam_veio(dev, 0, 0x23, 0x012a); /* Same everywhere */ - usb_ibmcam_veio(dev, 0, 0x03, 0x0106); - usb_ibmcam_veio(dev, 0, 0xf6, 0x0107); + usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1f); + usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x08, 0x0102); + usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0104); + usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x2f, 0x011c); + usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a); /* Same everywhere */ + usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0106); + usb_ibmcam_veio(ibmcam, 0, 0xf6, 0x0107); break; } return 0; /* TODO: return actual completion status! */ @@ -1441,16 +1477,16 @@ * This code adds finishing touches to the video data interface. * Here we configure the frame rate and turn on the LED. */ -static void usb_ibmcam_setup_after_video_if(struct usb_device *dev) +static void usb_ibmcam_setup_after_video_if(struct usb_ibmcam *ibmcam) { unsigned short internal_frame_rate; RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX); internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */ - usb_ibmcam_veio(dev, 0, 0x01, 0x0100); /* LED On */ - usb_ibmcam_veio(dev, 0, internal_frame_rate, 0x0111); - usb_ibmcam_veio(dev, 0, 0x01, 0x0114); - usb_ibmcam_veio(dev, 0, 0xc0, 0x010c); + usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100); /* LED On */ + usb_ibmcam_veio(ibmcam, 0, internal_frame_rate, 0x0111); + usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0114); + usb_ibmcam_veio(ibmcam, 0, 0xc0, 0x010c); } /* @@ -1459,16 +1495,16 @@ * This code tells camera to stop streaming. The interface remains * configured and bandwidth - claimed. */ -static void usb_ibmcam_setup_video_stop(struct usb_device *dev) +static void usb_ibmcam_setup_video_stop(struct usb_ibmcam *ibmcam) { - usb_ibmcam_veio(dev, 0, 0x00, 0x010c); - usb_ibmcam_veio(dev, 0, 0x00, 0x010c); - usb_ibmcam_veio(dev, 0, 0x01, 0x0114); - usb_ibmcam_veio(dev, 0, 0xc0, 0x010c); - usb_ibmcam_veio(dev, 0, 0x00, 0x010c); - usb_ibmcam_send_FF_04_02(dev); - usb_ibmcam_veio(dev, 1, 0x00, 0x0100); - usb_ibmcam_veio(dev, 0, 0x81, 0x0100); /* LED Off */ + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c); + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c); + usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0114); + usb_ibmcam_veio(ibmcam, 0, 0xc0, 0x010c); + usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c); + usb_ibmcam_send_FF_04_02(ibmcam); + usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100); + usb_ibmcam_veio(ibmcam, 0, 0x81, 0x0100); /* LED Off */ } /* @@ -1484,19 +1520,28 @@ static void usb_ibmcam_reinit_iso(struct usb_ibmcam *ibmcam, int do_stop) { if (do_stop) - usb_ibmcam_setup_video_stop(ibmcam->dev); + usb_ibmcam_setup_video_stop(ibmcam); - usb_ibmcam_veio(ibmcam->dev, 0, 0x0001, 0x0114); - usb_ibmcam_veio(ibmcam->dev, 0, 0x00c0, 0x010c); + usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0114); + usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c); usb_clear_halt(ibmcam->dev, ibmcam->video_endp); - usb_ibmcam_setup_after_video_if(ibmcam->dev); + usb_ibmcam_setup_after_video_if(ibmcam); } +/* + * ibmcam_init_isoc() + * + * History: + * 1/27/00 Used ibmcam->iface, ibmcam->ifaceAltActive instead of hardcoded values. + * Simplified by using for loop, allowed any number of URBs. + */ static int ibmcam_init_isoc(struct usb_ibmcam *ibmcam) { struct usb_device *dev = ibmcam->dev; - urb_t *urb; - int fx, err; + int i, err; + + if (!IBMCAM_IS_OPERATIONAL(ibmcam)) + return -EFAULT; ibmcam->compress = 0; ibmcam->curframe = -1; @@ -1504,8 +1549,10 @@ ibmcam->scratchlen = 0; /* Alternate interface 1 is is the biggest frame size */ - if (usb_set_interface(ibmcam->dev, 2, 1) < 0) { + i = usb_set_interface(dev, ibmcam->iface, ibmcam->ifaceAltActive); + if (i < 0) { printk(KERN_ERR "usb_set_interface error\n"); + ibmcam->last_error = i; return -EBUSY; } usb_ibmcam_change_lighting_conditions(ibmcam); @@ -1513,57 +1560,46 @@ usb_ibmcam_reinit_iso(ibmcam, 0); /* We double buffer the Iso lists */ - urb = usb_alloc_urb(FRAMES_PER_DESC); - - if (!urb) { - printk(KERN_ERR "ibmcam_init_isoc: usb_init_isoc ret %d\n", - 0); - return -ENOMEM; - } - ibmcam->sbuf[0].urb = urb; - urb->dev = dev; - urb->context = ibmcam; - urb->pipe = usb_rcvisocpipe(dev, ibmcam->video_endp); - urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ibmcam->sbuf[0].data; - urb->complete = ibmcam_isoc_irq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = ibmcam->iso_packet_len * FRAMES_PER_DESC; - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = ibmcam->iso_packet_len * fx; - urb->iso_frame_desc[fx].length = ibmcam->iso_packet_len; - } - urb = usb_alloc_urb(FRAMES_PER_DESC); - if (!urb) { - printk(KERN_ERR "ibmcam_init_isoc: usb_init_isoc ret %d\n", - 0); - return -ENOMEM; - } - ibmcam->sbuf[1].urb = urb; - urb->dev = dev; - urb->context = ibmcam; - urb->pipe = usb_rcvisocpipe(dev, ibmcam->video_endp); - urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ibmcam->sbuf[1].data; - urb->complete = ibmcam_isoc_irq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = ibmcam->iso_packet_len * FRAMES_PER_DESC; - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = ibmcam->iso_packet_len * fx; - urb->iso_frame_desc[fx].length = ibmcam->iso_packet_len; + + for (i=0; i < IBMCAM_NUMSBUF; i++) { + int j, k; + urb_t *urb; + + urb = usb_alloc_urb(FRAMES_PER_DESC); + if (urb == NULL) { + printk(KERN_ERR "ibmcam_init_isoc: usb_init_isoc() failed.\n"); + return -ENOMEM; + } + ibmcam->sbuf[i].urb = urb; + urb->dev = dev; + urb->context = ibmcam; + urb->pipe = usb_rcvisocpipe(dev, ibmcam->video_endp); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ibmcam->sbuf[i].data; + urb->complete = ibmcam_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = ibmcam->iso_packet_len * FRAMES_PER_DESC; + for (j=k=0; j < FRAMES_PER_DESC; j++, k += ibmcam->iso_packet_len) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = ibmcam->iso_packet_len; + } } - ibmcam->sbuf[1].urb->next = ibmcam->sbuf[0].urb; - ibmcam->sbuf[0].urb->next = ibmcam->sbuf[1].urb; - - err = usb_submit_urb(ibmcam->sbuf[0].urb); - if (err) - printk(KERN_ERR "ibmcam_init_isoc: usb_run_isoc(0) ret %d\n", - err); - err = usb_submit_urb(ibmcam->sbuf[1].urb); - if (err) - printk(KERN_ERR "ibmcam_init_isoc: usb_run_isoc(1) ret %d\n", - err); + /* Link URBs into a ring so that they invoke each other infinitely */ + for (i=0; i < IBMCAM_NUMSBUF; i++) { + if ((i+1) < IBMCAM_NUMSBUF) + ibmcam->sbuf[i].urb->next = ibmcam->sbuf[i+1].urb; + else + ibmcam->sbuf[i].urb->next = ibmcam->sbuf[0].urb; + } + + /* Submit all URBs */ + for (i=0; i < IBMCAM_NUMSBUF; i++) { + err = usb_submit_urb(ibmcam->sbuf[i].urb); + if (err) + printk(KERN_ERR "ibmcam_init_isoc: usb_run_isoc(%d) ret %d\n", + i, err); + } ibmcam->streaming = 1; // printk(KERN_DEBUG "streaming=1 ibmcam->video_endp=$%02x\n", ibmcam->video_endp); @@ -1578,28 +1614,39 @@ * * History: * 1/22/00 Corrected order of actions to work after surprise removal. + * 1/27/00 Used ibmcam->iface, ibmcam->ifaceAltInactive instead of hardcoded values. */ static void ibmcam_stop_isoc(struct usb_ibmcam *ibmcam) { - if (!ibmcam->streaming) + static const char proc[] = "ibmcam_stop_isoc"; + int i, j; + + if (!ibmcam->streaming || (ibmcam->dev == NULL)) return; /* Unschedule all of the iso td's */ - usb_unlink_urb(ibmcam->sbuf[1].urb); - usb_unlink_urb(ibmcam->sbuf[0].urb); - + for (i=0; i < IBMCAM_NUMSBUF; i++) { + j = usb_unlink_urb(ibmcam->sbuf[i].urb); + if (j < 0) + printk(KERN_ERR "%s: usb_unlink_urb() error %d.\n", proc, j); + } /* printk(KERN_DEBUG "streaming=0\n"); */ ibmcam->streaming = 0; /* Delete them all */ - usb_free_urb(ibmcam->sbuf[1].urb); - usb_free_urb(ibmcam->sbuf[0].urb); + for (i=0; i < IBMCAM_NUMSBUF; i++) + usb_free_urb(ibmcam->sbuf[i].urb); - usb_ibmcam_setup_video_stop(ibmcam->dev); + if (!ibmcam->remove_pending) { + usb_ibmcam_setup_video_stop(ibmcam); - /* Set packet size to 0 */ - if (usb_set_interface(ibmcam->dev, 2, 0) < 0) - printk(KERN_ERR "usb_set_interface error\n"); + /* Set packet size to 0 */ + j = usb_set_interface(ibmcam->dev, ibmcam->iface, ibmcam->ifaceAltInactive); + if (j < 0) { + printk(KERN_ERR "%s: usb_set_interface() error %d.\n", proc, j); + ibmcam->last_error = j; + } + } } static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum) @@ -1669,11 +1716,11 @@ * 1/22/00 Rewrote, moved scratch buffer allocation here. Now the * camera is also initialized here (once per connect), at * expense of V4L client (it waits on open() call). + * 1/27/00 Used IBMCAM_NUMSBUF as number of URB buffers. */ static int ibmcam_open(struct video_device *dev, int flags) { struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev; - const int nbuffers = 2; const int sb_size = FRAMES_PER_DESC * ibmcam->iso_packet_len; int i, err = 0; @@ -1683,11 +1730,11 @@ err = -EBUSY; else { /* Clean pointers so we know if we allocated something */ - for (i=0; i < nbuffers; i++) + for (i=0; i < IBMCAM_NUMSBUF; i++) ibmcam->sbuf[i].data = NULL; /* Allocate memory for the frame buffers */ - ibmcam->fbuf_size = nbuffers * MAX_FRAME_SIZE; + ibmcam->fbuf_size = IBMCAM_NUMFRAMES * MAX_FRAME_SIZE; ibmcam->fbuf = rvmalloc(ibmcam->fbuf_size); ibmcam->scratch = kmalloc(scratchbufsize, GFP_KERNEL); ibmcam->scratchlen = 0; @@ -1695,15 +1742,9 @@ err = -ENOMEM; else { /* Allocate all buffers */ - for (i=0; i < nbuffers; i++) { + for (i=0; i < IBMCAM_NUMFRAMES; i++) { ibmcam->frame[i].grabstate = FRAME_UNUSED; ibmcam->frame[i].data = ibmcam->fbuf + i*MAX_FRAME_SIZE; - - ibmcam->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); - if (ibmcam->sbuf[i].data == NULL) { - err = -ENOMEM; - break; - } /* * Set default sizes in case IOCTL (VIDIOCMCAPTURE) * is not used (using read() instead). @@ -1712,6 +1753,13 @@ ibmcam->frame[i].height = imgheight; ibmcam->frame[i].bytes_read = 0; } + for (i=0; i < IBMCAM_NUMSBUF; i++) { + ibmcam->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); + if (ibmcam->sbuf[i].data == NULL) { + err = -ENOMEM; + break; + } + } } if (err) { /* Have to free all that memory */ @@ -1723,7 +1771,7 @@ kfree(ibmcam->scratch); ibmcam->scratch = NULL; } - for (i=0; i < nbuffers; i++) { + for (i=0; i < IBMCAM_NUMSBUF; i++) { if (ibmcam->sbuf[i].data != NULL) { kfree (ibmcam->sbuf[i].data); ibmcam->sbuf[i].data = NULL; @@ -1762,10 +1810,12 @@ * * History: * 1/22/00 Moved scratch buffer deallocation here. + * 1/27/00 Used IBMCAM_NUMSBUF as number of URB buffers. */ static void ibmcam_close(struct video_device *dev) { struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev; + int i; down(&ibmcam->lock); @@ -1773,12 +1823,16 @@ rvfree(ibmcam->fbuf, ibmcam->fbuf_size); kfree(ibmcam->scratch); - kfree(ibmcam->sbuf[1].data); - kfree(ibmcam->sbuf[0].data); + for (i=0; i < IBMCAM_NUMSBUF; i++) + kfree(ibmcam->sbuf[i].data); ibmcam->user--; MOD_DEC_USE_COUNT; + if (ibmcam->remove_pending) { + printk(KERN_INFO "ibmcam_close: Final disconnect.\n"); + usb_ibmcam_release(ibmcam); + } up(&ibmcam->lock); } @@ -1804,7 +1858,7 @@ { struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev; - if (ibmcam->remove_pending) + if (!IBMCAM_IS_OPERATIONAL(ibmcam)) return -EFAULT; switch (cmd) { @@ -1959,6 +2013,8 @@ { int ntries; redo: + if (!IBMCAM_IS_OPERATIONAL(ibmcam)) + return -EIO; ntries = 0; do { interruptible_sleep_on(&ibmcam->frame[frame].wq); @@ -2042,10 +2098,7 @@ if (debug >= 1) printk(KERN_DEBUG "ibmcam_read: %ld bytes, noblock=%d\n", count, noblock); - if (ibmcam->remove_pending) - return -EFAULT; - - if (!dev || !buf) + if (!IBMCAM_IS_OPERATIONAL(ibmcam) || (buf == NULL)) return -EFAULT; /* See if a frame is completed, then use it. */ @@ -2073,6 +2126,8 @@ frame = &ibmcam->frame[frmx]; restart: + if (!IBMCAM_IS_OPERATIONAL(ibmcam)) + return -EIO; while (frame->grabstate == FRAME_GRABBING) { interruptible_sleep_on((void *)&frame->wq); if (signal_pending(current)) @@ -2120,7 +2175,7 @@ unsigned long start = (unsigned long)adr; unsigned long page, pos; - if (ibmcam->remove_pending) + if (!IBMCAM_IS_OPERATIONAL(ibmcam)) return -EFAULT; if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) @@ -2169,6 +2224,7 @@ RESTRICT_TO_RANGE(init_contrast, 0, 255); RESTRICT_TO_RANGE(init_color, 0, 255); RESTRICT_TO_RANGE(init_hue, 0, 255); + RESTRICT_TO_RANGE(hue_correction, 0, 255); memset(&ibmcam->vpic, 0, sizeof(ibmcam->vpic)); memset(&ibmcam->vpic_old, 0x55, sizeof(ibmcam->vpic_old)); @@ -2200,6 +2256,27 @@ } /* + * usb_ibmcam_release() + * + * This code searches the array of preallocated (static) structures + * and returns index of the first one that isn't in use. Returns -1 + * if there are no free structures. + * + * History: + * 1/27/00 Created. + */ +static int ibmcam_find_struct(void) +{ + int u; + + for (u = 0; u < MAX_IBMCAM; u++) { + if (!cams[u].ibmcam_used) /* This one is free */ + return u; + } + return -1; +} + +/* * usb_ibmcam_probe() * * This procedure queries device descriptor and accepts the interface @@ -2207,11 +2284,13 @@ * * History: * 1/22/00 Moved camera init code to ibmcam_open() + * 1/27/00 Changed to use static structures, added locking. */ static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_ibmcam *ibmcam = NULL; struct usb_interface_descriptor *interface; + int devnum; if (debug >= 1) printk(KERN_DEBUG "ibmcam_probe(%p,%u.)\n", dev, ifnum); @@ -2225,6 +2304,8 @@ (dev->descriptor.idProduct != 0x8080)) return NULL; + interface = &dev->actconfig->interface[ifnum].altsetting[0]; + /* Camera confirmed. We claim only interface 2 (video data) */ if (ifnum != 2) return NULL; @@ -2232,26 +2313,32 @@ /* We found an IBM camera */ printk(KERN_INFO "IBM USB camera found (interface %u.)\n", ifnum); - if (debug >= 1) - printk(KERN_DEBUG "ibmcam_probe: new ibmcam alloc\n"); - ibmcam = kmalloc(sizeof(*ibmcam), GFP_KERNEL); - if (ibmcam == NULL) { - printk(KERN_ERR "couldn't kmalloc ibmcam struct\n"); + devnum = ibmcam_find_struct(); + if (devnum == -1) { + printk(KERN_INFO "IBM USB camera driver: Too many devices!\n"); return NULL; } - memset(ibmcam, 0, sizeof(struct usb_ibmcam)); + ibmcam = &cams[devnum]; + + down(&ibmcam->lock); + ibmcam->ibmcam_used = 1; /* In use now */ + ibmcam->remove_pending = 0; + ibmcam->last_error = 0; ibmcam->dev = dev; - interface = &dev->actconfig->interface[ifnum].altsetting[0]; - ibmcam->iface = interface->bInterfaceNumber; + ibmcam->iface = ifnum; + ibmcam->ifaceAltInactive = 0; + ibmcam->ifaceAltActive = 1; ibmcam->video_endp = 0x82; - init_waitqueue_head (&ibmcam->remove_ok); ibmcam->iso_packet_len = 1014; + ibmcam->compress = 0; + ibmcam->user=0; - memcpy(&ibmcam->vdev, &ibmcam_template, sizeof(ibmcam_template)); usb_ibmcam_configure_video(ibmcam); + up (&ibmcam->lock); - init_waitqueue_head(&ibmcam->frame[0].wq); - init_waitqueue_head(&ibmcam->frame[1].wq); +#if IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED + MOD_INC_USE_COUNT; +#endif if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER) == -1) { printk(KERN_ERR "video_register_device failed\n"); @@ -2260,14 +2347,27 @@ if (debug > 1) printk(KERN_DEBUG "video_register_device() successful\n"); - ibmcam->compress = 0; - ibmcam->user=0; - init_MUTEX(&ibmcam->lock); /* to 1 == available */ - return ibmcam; } /* + * usb_ibmcam_release() + * + * This code does final release of struct usb_ibmcam. This happens + * after the device is disconnected -and- all clients closed their files. + * + * History: + * 1/27/00 Created. + */ +static void usb_ibmcam_release(struct usb_ibmcam *ibmcam) +{ + video_unregister_device(&ibmcam->vdev); + if (debug > 0) + printk(KERN_DEBUG "usb_ibmcam_release: Video unregistered.\n"); + ibmcam->ibmcam_used = 0; +} + +/* * usb_ibmcam_disconnect() * * This procedure stops all driver activity, deallocates interface-private @@ -2278,40 +2378,32 @@ * * History: * 1/22/00 Added polling of MOD_IN_USE to delay removal until all users gone. + * 1/27/00 Reworked to allow pending disconnects; see ibmcam_close() */ static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr) { static const char proc[] = "usb_ibmcam_disconnect"; struct usb_ibmcam *ibmcam = (struct usb_ibmcam *) ptr; - wait_queue_head_t wq; /* Wait here until removal is safe */ if (debug > 0) printk(KERN_DEBUG "%s(%p,%p.)\n", proc, dev, ptr); - init_waitqueue_head(&wq); + down(&ibmcam->lock); ibmcam->remove_pending = 1; /* Now all ISO data will be ignored */ /* At this time we ask to cancel outstanding URBs */ ibmcam_stop_isoc(ibmcam); - if (MOD_IN_USE) { - printk(KERN_INFO "%s: In use, disconnect pending.\n", proc); - while (MOD_IN_USE) - interruptible_sleep_on_timeout (&wq, HZ); - printk(KERN_INFO "%s: Released, wait.\n", proc); -// interruptible_sleep_on_timeout (&wq, HZ*10); - } - video_unregister_device(&ibmcam->vdev); - printk(KERN_INFO "%s: Video dereg'd, wait.\n", proc); -// interruptible_sleep_on_timeout (&wq, HZ*10); - - /* Free the memory */ - if (debug > 0) - printk(KERN_DEBUG "%s: freeing ibmcam=%p\n", proc, ibmcam); - kfree(ibmcam); + ibmcam->dev = NULL; /* USB device is no more */ - printk(KERN_INFO "%s: Memory freed, wait.\n", proc); -// interruptible_sleep_on_timeout (&wq, HZ*10); +#if IBMCAM_LOCKS_DRIVER_WHILE_DEVICE_IS_PLUGGED + MOD_DEC_USE_COUNT; +#endif + if (ibmcam->user) + printk(KERN_INFO "%s: In use, disconnect pending.\n", proc); + else + usb_ibmcam_release(ibmcam); + up(&ibmcam->lock); printk(KERN_INFO "IBM USB camera disconnected.\n"); } @@ -2323,8 +2415,30 @@ { NULL, NULL } }; +/* + * usb_ibmcam_init() + * + * This code is run to initialize the driver. + * + * History: + * 1/27/00 Reworked to use statically allocated usb_ibmcam structures. + */ int usb_ibmcam_init(void) { + unsigned i, u; + + /* Initialize struct */ + for (u = 0; u < MAX_IBMCAM; u++) { + struct usb_ibmcam *ibmcam = &cams[u]; + memset (ibmcam, 0, sizeof(struct usb_ibmcam)); + + init_waitqueue_head (&ibmcam->remove_ok); + for (i=0; i < IBMCAM_NUMFRAMES; i++) + init_waitqueue_head(&ibmcam->frame[i].wq); + init_MUTEX(&ibmcam->lock); /* to 1 == available */ + ibmcam->dev = NULL; + memcpy(&ibmcam->vdev, &ibmcam_template, sizeof(ibmcam_template)); + } return usb_register(&ibmcam_driver); } diff -u --recursive --new-file v2.3.42/linux/drivers/usb/ibmcam.h linux/drivers/usb/ibmcam.h --- v2.3.42/linux/drivers/usb/ibmcam.h Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/ibmcam.h Mon Feb 7 19:15:56 2000 @@ -119,6 +119,17 @@ interruptible_sleep_on_timeout (&wq, HZ*3); \ } +/* + * This macro checks if ibmcam is still operational. The 'ibmcam' + * pointer must be valid, ibmcam->dev must be valid, we are not + * removing the device and the device has not erred on us. + */ +#define IBMCAM_IS_OPERATIONAL(ibm_cam) (\ + (ibm_cam != NULL) && \ + ((ibm_cam)->dev != NULL) && \ + ((ibm_cam)->last_error == 0) && \ + (!(ibm_cam)->remove_pending)) + enum { STATE_SCANNING, /* Scanning for header */ STATE_LINES, /* Parsing lines */ @@ -167,14 +178,17 @@ /* Device structure */ struct usb_device *dev; - unsigned char iface; + unsigned char iface; /* Video interface number */ + unsigned char ifaceAltActive, ifaceAltInactive; /* Alt settings */ struct semaphore lock; int user; /* user count for exclusive use */ + int ibmcam_used; /* Is this structure in use? */ int initialized; /* Had we already sent init sequence? */ int streaming; /* Are we streaming Isochronous? */ int grabbing; /* Are we grabbing? */ + int last_error; /* What calamity struck us? */ int compress; /* Should the next frame be compressed? */ diff -u --recursive --new-file v2.3.42/linux/drivers/usb/inode.c linux/drivers/usb/inode.c --- v2.3.42/linux/drivers/usb/inode.c Fri Jan 21 18:19:17 2000 +++ linux/drivers/usb/inode.c Wed Feb 9 11:42:35 2000 @@ -400,21 +400,21 @@ } static struct file_operations usbdevfs_root_file_operations = { - readdir: usbdevfs_root_readdir + readdir: usbdevfs_root_readdir, }; static struct inode_operations usbdevfs_root_inode_operations = { default_file_ops: &usbdevfs_root_file_operations, - lookup: usbdevfs_root_lookup + lookup: usbdevfs_root_lookup, }; static struct file_operations usbdevfs_bus_file_operations = { - readdir: usbdevfs_bus_readdir + readdir: usbdevfs_bus_readdir, }; static struct inode_operations usbdevfs_bus_inode_operations = { default_file_ops: &usbdevfs_bus_file_operations, - lookup: usbdevfs_bus_lookup + lookup: usbdevfs_bus_lookup, }; static void usbdevfs_read_inode(struct inode *inode) diff -u --recursive --new-file v2.3.42/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c --- v2.3.42/linux/drivers/usb/keybdev.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/keybdev.c Thu Feb 10 12:28:01 2000 @@ -112,7 +112,7 @@ #error "Cannot generate rawmode keyboard for your architecture yet." #endif - mark_bh(KEYBOARD_BH); + tasklet_schedule(&keyboard_tasklet); } static int keybdev_connect(struct input_handler *handler, struct input_dev *dev) diff -u --recursive --new-file v2.3.42/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- v2.3.42/linux/drivers/usb/ov511.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/ov511.c Wed Feb 9 11:51:13 2000 @@ -1,6 +1,7 @@ /* * OmniVision OV511 Camera-to-USB Bridge Driver - * Copyright 1999/2000 Mark W. McClelland + * Copyright (c) 1999/2000 Mark W. McClelland + * Many improvements by Bret Wallach * * Based on the Linux CPiA driver. * @@ -11,7 +12,7 @@ * DEBUG - Debugging code. * FIXME - Something that is broken or needs improvement. * - * Version: 1.06 + * Version: 1.07 * * Please see the file: linux/Documentation/usb/ov511.txt * and the website at: http://people.delphi.com/mmcclelland/linux/ @@ -58,7 +59,7 @@ #include #include #include - +#include #include #include "usb.h" @@ -70,9 +71,9 @@ /* Video Size 640 x 480 x 3 bytes for RGB */ #define MAX_FRAME_SIZE (640 * 480 * 3) +#define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval)) -// FIXME - Force CIF to make some apps happy for the moment. Should find a -// better way to do this. +// FIXME - Should find a better way to do this. #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 480 @@ -206,7 +207,7 @@ 0, (__u16)reg, &value, 1, HZ); #if 0 - PDEBUG("reg write: 0x%02X:0x%02X", reg, value); + PDEBUG("reg write: 0x%02X:0x%02X, 0x%x", reg, value, rc); #endif return rc; @@ -261,10 +262,10 @@ if((rc&2) == 0) /* Ack? */ break; - +#if 0 /* I2C abort */ ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); - +#endif if (--retries < 0) return -1; } @@ -331,6 +332,58 @@ return (value); } + +// This version doesn't always work +#if 0 + /* returns: negative is error, pos or zero is data */ + int ov511_i2c_read(struct usb_device *dev, unsigned char reg) + { + int rc, value; + + /* Select camera register */ + rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + if (rc < 0) return rc; + + + /* Initiate 2-byte write cycle */ + rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); + if (rc < 0) return rc; + + + /* Initiate 2-byte read cycle */ + rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + if (rc < 0) return rc; + + value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + #if 0 + PDEBUG("i2c read: 0x%02X:0x%02X", reg, value); + #endif + + return (value); + } +#endif + +static int ov511_write_regvals(struct usb_device *dev, + struct ov511_regvals * pRegvals) +{ + int ret; + while(pRegvals->bus != OV511_DONE_BUS) { + if (pRegvals->bus == OV511_REG_BUS) { + if ((ret = ov511_reg_write(dev, pRegvals->reg, + pRegvals->val)) < 0) + return ret; + } else if (pRegvals->bus == OV511_I2C_BUS) { + if ((ret = ov511_i2c_write(dev, pRegvals->reg, + pRegvals->val)) < 0) + return ret; + } else { + err("Bad regval array"); + } + pRegvals++; + } + return 0; +} + #if 0 static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn) { @@ -384,18 +437,6 @@ } #endif -int ov511_i2c_reset(struct usb_device *dev) -{ - int rc; - - PDEBUG("Reset 7610"); - rc = ov511_i2c_write(dev, 0x12, 0x80); - if (rc < 0) - err("i2c reset: command failed"); - - return rc; -} - int ov511_reset(struct usb_device *dev, unsigned char reset_type) { int rc; @@ -480,6 +521,21 @@ static inline int ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p) { + int ret; + + /* Stop the camera */ + if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) { + err("reset: command failed"); + return -EIO; + } + + if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_COM_B)) < 0) + return -EIO; +#if 0 + if(ov511_i2c_write(ov511->dev, OV7610_REG_COM_B, ret & 0xfe) < 0) + return -EIO; +#endif + if(ov511_i2c_write(ov511->dev, OV7610_REG_SAT, p->colour >> 8) < 0) return -EIO; @@ -489,6 +545,12 @@ if(ov511_i2c_write(ov511->dev, OV7610_REG_BRT, p->brightness >> 8) < 0) return -EIO; + /* Restart the camera */ + if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x0) < 0) { + err("reset: command failed"); + return -EIO; + } + return 0; } @@ -497,6 +559,12 @@ { int ret; + /* Stop the camera */ + if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) { + err("reset: command failed"); + return -EIO; + } + if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_SAT)) < 0) return -EIO; p->colour = ret << 8; @@ -511,43 +579,71 @@ p->depth = 24; p->palette = VIDEO_PALETTE_RGB24; + /* Restart the camera */ + if (ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_RESET, 0x0) < 0) { + err("reset: command failed"); + return -EIO; + } + return 0; } static int ov511_mode_init_regs(struct usb_ov511 *ov511, - int width, int height, int mode) + int width, int height, int mode, int sub_flag) { int rc = 0; struct usb_device *dev = ov511->dev; #if 0 - PDEBUG("ov511_mode_init_regs(ov511, %d, %d, %d)", width, height, mode); + PDEBUG("ov511_mode_init_regs(ov511, %d, %d, %d, %d)", + width, height, mode, sub_flag); #endif - ov511_set_packet_size(ov511, 0); - /* Set mode consistent registers */ - ov511_i2c_write(dev, 0x0f, 0x03); - ov511_i2c_write(dev, 0x10, 0xff); - ov511_i2c_write(dev, 0x13, 0x01); - ov511_i2c_write(dev, 0x16, 0x06); - ov511_i2c_write(dev, 0x20, 0x1c); - ov511_i2c_write(dev, 0x24, 0x2e); /* 10 */ - ov511_i2c_write(dev, 0x25, 0x7c); /* 8a */ - ov511_i2c_write(dev, 0x26, 0x00); /* was 0x70 */ - ov511_i2c_write(dev, 0x28, 0x24); /* 24 */ - ov511_i2c_write(dev, 0x2b, 0xac); - ov511_i2c_write(dev, 0x2c, 0xfe); - ov511_i2c_write(dev, 0x2d, 0x93); - ov511_i2c_write(dev, 0x34, 0x8b); +// ov511_set_packet_size(ov511, 0); + if (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d) < 0) { + err("reset: command failed"); + return -EIO; + } + + if (mode == VIDEO_PALETTE_GREY) { + ov511_reg_write(dev, 0x16, 0); + ov511_i2c_write(dev, 0xe, 0x44); + ov511_i2c_write(dev, 0x13, 0x21); + } else { + ov511_reg_write(dev, 0x16, 1); + ov511_i2c_write(dev, 0xe, 0x4); + ov511_i2c_write(dev, 0x13, 0x1); + } if (width == 640 && height == 480) { - ov511_reg_write(dev, 0x12, 0x4f); - ov511_reg_write(dev, 0x13, 0x3d); + if (sub_flag) { + ov511_i2c_write(ov511->dev, 0x17, 0x38+(ov511->subx>>2)); + ov511_i2c_write(ov511->dev, 0x18, + 0x3a+((ov511->subx+ov511->subw)>>2)); + ov511_i2c_write(ov511->dev, 0x19, 0x5+(ov511->suby>>1)); + ov511_i2c_write(ov511->dev, 0x1a, + 0x5+((ov511->suby+ov511->subh)>>1)); + ov511_reg_write(ov511->dev, 0x12, (ov511->subw>>3)-1); + ov511_reg_write(ov511->dev, 0x13, (ov511->subh>>3)-1); + ov511_i2c_write(dev, 0x11, 0x01); + } else { + ov511_i2c_write(ov511->dev, 0x17, 0x38); + ov511_i2c_write(ov511->dev, 0x18, 0x3a + (640>>2)); + ov511_i2c_write(ov511->dev, 0x19, 0x5); + ov511_i2c_write(ov511->dev, 0x1c, + (480>>1)); + ov511_reg_write(dev, 0x12, 0x4f); + ov511_reg_write(dev, 0x13, 0x3d); + if (mode == VIDEO_PALETTE_GREY) { + ov511_i2c_write(dev, 0x11, 4); /* check */ + } else { + ov511_i2c_write(dev, 0x11, 6); /* check */ + } + } + ov511_reg_write(dev, 0x14, 0x00); ov511_reg_write(dev, 0x15, 0x00); ov511_reg_write(dev, 0x18, 0x03); - ov511_i2c_write(dev, 0x11, 0x01); ov511_i2c_write(dev, 0x12, 0x24); ov511_i2c_write(dev, 0x14, 0x04); ov511_i2c_write(dev, 0x35, 0x9e); @@ -558,7 +654,12 @@ ov511_reg_write(dev, 0x15, 0x00); ov511_reg_write(dev, 0x18, 0x03); - ov511_i2c_write(dev, 0x11, 0x00); + if (mode == VIDEO_PALETTE_GREY) { + ov511_i2c_write(dev, 0x11, 1); /* check */ + } else { + ov511_i2c_write(dev, 0x11, 1); /* check */ + } + ov511_i2c_write(dev, 0x12, 0x04); ov511_i2c_write(dev, 0x14, 0x24); ov511_i2c_write(dev, 0x35, 0x1e); @@ -566,7 +667,13 @@ err("Unknown mode (%d, %d): %d", width, height, mode); rc = -EINVAL; } - ov511_set_packet_size(ov511, 993); + +// ov511_set_packet_size(ov511, 993); + + if (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00) < 0) { + PDEBUG("reset: command failed"); + return -EIO; + } return rc; } @@ -633,25 +740,20 @@ #define HDIV 8 #define WDIV (256/HDIV) -static void ov511_parse_data(unsigned char * pIn0, - unsigned char * pOut0, - int iWidth, - int iSegment) - + +static void ov511_parse_data_rgb24(unsigned char * pIn0, + unsigned char * pOut0, + int iOutY, + int iOutUV, + int iHalf, + int iWidth) + { #ifndef OV511_DUMPPIX int k, l, m; unsigned char * pIn; unsigned char * pOut, * pOut1; - int iHalf = (iSegment / (iWidth / 32)) & 1; - int iY = iSegment / (iWidth / WDIV); - int jY = iSegment - iY * (iWidth / WDIV); - int iOutY = (iY*HDIV*iWidth + jY*WDIV) * 3; - int iUV = iSegment / (iWidth / WDIV * 2); - int jUV = iSegment - iUV * (iWidth / WDIV * 2); - int iOutUV = (iUV*HDIV*2*iWidth + jUV*WDIV/2) * 3; - /* Just copy the Y's if in the first stripe */ if (!iHalf) { pIn = pIn0 + 128; @@ -723,13 +825,49 @@ #else /* Just dump pix data straight out for debug */ int i; - pOut0 += iSegment * 384; + pOut0 += iSegmentY * 384; for(i=0; i<384; i++) { *pOut0++ = *pIn0++; } #endif } +/*************************************************************** + +For 640x480 RAW BW images, data shows up in 1200 256 byte segments. +The segments represent 4 squares of 8x8 pixels as +follows: + + 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 + 8 9 ... 15 72 73 ... 79 200 201 ... 207 + ... ... ... + 56 57 ... 63 120 121 127 248 249 ... 255 + +****************************************************************/ +static void ov511_parse_data_grey(unsigned char * pIn0, + unsigned char * pOut0, + int iOutY, + int iWidth) + +{ + int k, l, m; + unsigned char * pIn; + unsigned char * pOut, * pOut1; + + pIn = pIn0; + pOut = pOut0 + iOutY; + for(k=0; k<4; k++) { + pOut1 = pOut; + for(l=0; l<8; l++) { + for(m=0; m<8; m++) { + *pOut1++ = *pIn++; + } + pOut1 += iWidth - 8; + } + pOut += 8; + } +} + static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb) { unsigned char *cdata; @@ -741,12 +879,13 @@ int n = urb->iso_frame_desc[i].actual_length; int st = urb->iso_frame_desc[i].status; urb->iso_frame_desc[i].actual_length = 0; - urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].status = 0; cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; aPackNum[i] = n ? cdata[992] : -1; if (!n || ov511->curframe == -1) continue; + if (st) PDEBUG("data error: [%d] len=%d, status=%d", i, n, st); @@ -757,33 +896,35 @@ cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 && (cdata[8] & 8) && (cdata[8] & 0x80)) { + struct timeval *ts; + ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE); + do_gettimeofday(ts); #if 0 - PDEBUG("Found Frame End!, packnum = %d", (int)(cdata[992])); - PDEBUG("Current frame = %d", ov511->curframe); + PDEBUG("Frame End, curframe = %d, packnum=%d, hw=%d, vw=%d", + ov511->curframe, (int)(cdata[992]), + (int)(cdata[9]), (int)(cdata[10])); #endif if (frame->scanstate == STATE_LINES) { int iFrameNext; + frame->grabstate = FRAME_DONE; if (waitqueue_active(&frame->wq)) { + frame->grabstate = FRAME_DONE; + wake_up_interruptible(&frame->wq); + } + /* If next frame is ready or grabbing, point to it */ + iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; + if (ov511->frame[iFrameNext].grabstate== FRAME_READY || + ov511->frame[iFrameNext].grabstate== FRAME_GRABBING) { + ov511->curframe = iFrameNext; + ov511->frame[iFrameNext].scanstate = STATE_SCANNING; + } else { #if 0 - PDEBUG("About to wake up waiting processes"); -#endif - frame->grabstate = FRAME_DONE; - wake_up_interruptible(&frame->wq); - } - /* If next frame is ready or grabbing, point to it */ - iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES; - if (ov511->frame[iFrameNext].grabstate== FRAME_READY || - ov511->frame[iFrameNext].grabstate== FRAME_GRABBING) { - ov511->curframe = iFrameNext; - frame->scanstate = STATE_SCANNING; - } else { -#if 0 - PDEBUG("Frame not ready? state = %d", - ov511->frame[iFrameNext].grabstate); + PDEBUG("Frame not ready? state = %d", + ov511->frame[iFrameNext].grabstate); #endif - ov511->curframe = -1; - } + ov511->curframe = -1; + } } } @@ -792,8 +933,8 @@ cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 && (cdata[8] & 8)) { #if 0 - PDEBUG("ov511: Found Frame Start!, packnum = %d", (int)(cdata[992])); - PDEBUG("ov511: Frame Header Byte = 0x%x", (int)(cdata[8])); + PDEBUG("ov511: Found Frame Start!, framenum = %d", + ov511->curframe); #endif frame->scanstate = STATE_LINES; frame->segment = 0; @@ -808,26 +949,67 @@ if (frame->segment) { pData = ov511->scratch; iPix = - ov511->scratchlen; - memmove(pData + ov511->scratchlen, cdata, iPix+384); - } else { + memmove(pData + ov511->scratchlen, cdata, + iPix+frame->segsize); + } else { pData = &cdata[iPix = 9]; - } + } /* Parse the segments */ - while(iPix <= 992 - 384 && + while(iPix <= 992 - frame->segsize && frame->segment < frame->width * frame->height / 256) { - ov511_parse_data(pData, frame->data, - frame->width, - frame->segment); + int iSegY; + int iSegUV; + int iY, jY, iUV, jUV; + int iOutY, iOutUV; + unsigned char * pOut; + + iSegY = iSegUV = frame->segment; + pOut = frame->data; + frame->segment++; - iPix += 384; + iPix += frame->segsize; + + if (frame->sub_flag) { + int iSeg1; + iSeg1 = iSegY / (ov511->subw / 32); + iSeg1 *= frame->width / 32; + iSegY = iSeg1 + (iSegY % (ov511->subw / 32)); + if (iSegY >= frame->width * ov511->subh / 256) + break; + + iSeg1 = iSegUV / (ov511->subw / 16); + iSeg1 *= frame->width / 16; + iSegUV = iSeg1 + (iSegUV % (ov511->subw / 16)); + + pOut += (ov511->subx + + ov511->suby * frame->width) * frame->depth; + } + + iY = iSegY / (frame->width / WDIV); + jY = iSegY - iY * (frame->width / WDIV); + iOutY = (iY*HDIV*frame->width + jY*WDIV) * frame->depth; + iUV = iSegUV / (frame->width / WDIV * 2); + jUV = iSegUV - iUV * (frame->width / WDIV * 2); + iOutUV = (iUV*HDIV*2*frame->width + jUV*WDIV/2) * frame->depth; + + if (frame->format == VIDEO_PALETTE_GREY) { + ov511_parse_data_grey(pData, pOut, iOutY, frame->width); + } else if (frame->format == VIDEO_PALETTE_RGB24) { + ov511_parse_data_rgb24(pData, pOut, iOutY, iOutUV, iY & 1, + frame->width); + } pData = &cdata[iPix]; - } + } /* Save extra data for next time */ if (frame->segment < frame->width * frame->height / 256) { - memmove(ov511->scratch, pData, 992 - iPix); ov511->scratchlen = 992 - iPix; + if (ov511->scratchlen < frame->segsize) { + memmove(ov511->scratch, pData, ov511->scratchlen); + } else { + ov511->scratchlen = 0; + } } } } @@ -845,7 +1027,9 @@ int len; struct usb_ov511 *ov511 = urb->context; struct ov511_sbuf *sbuf; - int i; + + if (!ov511->dev) + return; if (!ov511->streaming) { PDEBUG("hmmm... not streaming, but got interrupt\n"); @@ -855,14 +1039,10 @@ sbuf = &ov511->sbuf[ov511->cursbuf]; /* Copy the data received into our scratch buffer */ - if (ov511->curframe >= 0) { + if (ov511->curframe >= 0) len = ov511_move_data(ov511, urb); - } - - for (i = 0; i < FRAMES_PER_DESC; i++) { - sbuf->urb->iso_frame_desc[i].status = 0; - sbuf->urb->iso_frame_desc[i].actual_length = 0; - } + else if (waitqueue_active(&ov511->wq)) + wake_up_interruptible(&ov511->wq); /* Move to the next sbuf */ ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF; @@ -872,7 +1052,6 @@ static int ov511_init_isoc(struct usb_ov511 *ov511) { - struct usb_device *dev = ov511->dev; urb_t *urb; int fx, err; @@ -891,9 +1070,9 @@ return -ENOMEM; } ov511->sbuf[0].urb = urb; - urb->dev = dev; + urb->dev = ov511->dev; urb->context = ov511; - urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); + urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS); urb->transfer_flags = USB_ISO_ASAP; urb->transfer_buffer = ov511->sbuf[0].data; urb->complete = ov511_isoc_irq; @@ -910,9 +1089,9 @@ return -ENOMEM; } ov511->sbuf[1].urb = urb; - urb->dev = dev; + urb->dev = ov511->dev; urb->context = ov511; - urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); + urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS); urb->transfer_flags = USB_ISO_ASAP; urb->transfer_buffer = ov511->sbuf[1].data; urb->complete = ov511_isoc_irq; @@ -928,10 +1107,10 @@ err = usb_submit_urb(ov511->sbuf[0].urb); if (err) - err("ov511_init_isoc: usb_run_isoc(0) ret %d", err); + err("ov511_init_isoc: usb_submit_urb(0) ret %d", err); err = usb_submit_urb(ov511->sbuf[1].urb); if (err) - err("ov511_init_isoc: usb_run_isoc(1) ret %d", err); + err("ov511_init_isoc: usb_submit_urb(1) ret %d", err); ov511->streaming = 1; @@ -941,27 +1120,37 @@ static void ov511_stop_isoc(struct usb_ov511 *ov511) { - if (!ov511->streaming) + if (!ov511->streaming || !ov511->dev) return; ov511_set_packet_size(ov511, 0); - - /* Unschedule all of the iso td's */ - usb_unlink_urb(ov511->sbuf[1].urb); - usb_unlink_urb(ov511->sbuf[0].urb); ov511->streaming = 0; - /* Delete them all */ - usb_free_urb(ov511->sbuf[1].urb); - usb_free_urb(ov511->sbuf[0].urb); + /* Unschedule all of the iso td's */ + if (ov511->sbuf[1].urb) { + ov511->sbuf[1].urb->next = NULL; + usb_unlink_urb(ov511->sbuf[1].urb); + usb_free_urb(ov511->sbuf[1].urb); + ov511->sbuf[1].urb = NULL; + } + if (ov511->sbuf[0].urb) { + ov511->sbuf[0].urb->next = NULL; + usb_unlink_urb(ov511->sbuf[0].urb); + usb_free_urb(ov511->sbuf[0].urb); + ov511->sbuf[0].urb = NULL; + } } static int ov511_new_frame(struct usb_ov511 *ov511, int framenum) { +#if 1 struct ov511_frame *frame; int width, height; + if (!ov511->dev) + return -1; + /* If we're not grabbing a frame right now and the other frame is */ /* ready to be grabbed into, then use it instead */ if (ov511->curframe == -1) { @@ -988,15 +1177,15 @@ if (height > DEFAULT_HEIGHT) height = DEFAULT_HEIGHT; height = (height / 4) * 4; /* Multiple of 4 */ - + // /* We want a fresh frame every 30 we get */ // ov511->compress = (ov511->compress + 1) % 30; +#endif return 0; } - /* Video 4 Linux API */ static int ov511_open(struct video_device *dev, int flags) { @@ -1004,23 +1193,24 @@ struct usb_ov511 *ov511 = (struct usb_ov511 *)dev; PDEBUG("ov511_open"); - + down(&ov511->lock); if (ov511->user) goto out_unlock; - + ov511->frame[0].grabstate = FRAME_UNUSED; ov511->frame[1].grabstate = FRAME_UNUSED; err = -ENOMEM; - - /* Allocate memory for the frame buffers */ - ov511->fbuf = rvmalloc(2 * MAX_FRAME_SIZE); + + /* Allocate memory for the frame buffers */ + ov511->fbuf = rvmalloc(2 * MAX_DATA_SIZE); if (!ov511->fbuf) goto open_err_ret; ov511->frame[0].data = ov511->fbuf; - ov511->frame[1].data = ov511->fbuf + MAX_FRAME_SIZE; + ov511->frame[1].data = ov511->fbuf + MAX_DATA_SIZE; + ov511->sub_flag = 0; PDEBUG("frame [0] @ %p", ov511->frame[0].data); PDEBUG("frame [1] @ %p", ov511->frame[1].data); @@ -1051,7 +1241,7 @@ open_err_on1: kfree (ov511->sbuf[0].data); open_err_on0: - rvfree(ov511->fbuf, 2 * MAX_FRAME_SIZE); + rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE); open_err_ret: return err; out_unlock: @@ -1073,12 +1263,17 @@ ov511_stop_isoc(ov511); - rvfree(ov511->fbuf, 2 * MAX_FRAME_SIZE); + rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE); kfree(ov511->sbuf[1].data); kfree(ov511->sbuf[0].data); up(&ov511->lock); + + if (!ov511->dev) { + video_unregister_device(&ov511->vdev); + kfree(ov511); + } } static int ov511_init_done(struct video_device *dev) @@ -1091,13 +1286,16 @@ return -EINVAL; } -// FIXME - Needs much work!!! static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg) { struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev; #if 0 PDEBUG("IOCtl: 0x%X", cmd); #endif + + if (!ov511->dev) + return -EIO; + switch (cmd) { case VIDIOCGCAP: { @@ -1109,8 +1307,8 @@ b.audios = 0; b.maxwidth = DEFAULT_WIDTH; b.maxheight = DEFAULT_HEIGHT; - b.minwidth = 8; - b.minheight = 4; + b.minwidth = 32; + b.minheight = 16; if (copy_to_user(arg, &b, sizeof(b))) return -EFAULT; @@ -1173,6 +1371,42 @@ return 0; } + case VIDIOCGCAPTURE: + { + int vf; + if (copy_from_user(&vf, arg, sizeof(vf))) + return -EFAULT; + ov511->sub_flag = vf; + return 0; + } + case VIDIOCSCAPTURE: + { + struct video_capture vc; + + if (copy_from_user(&vc, arg, sizeof(vc))) + return -EFAULT; + if (vc.flags) + return -EINVAL; + if (vc.decimation) + return -EINVAL; + vc.x /= 4; + vc.x *= 4; + vc.y /= 2; + vc.y *= 2; + vc.width /= 32; + vc.width *= 32; + if (vc.width == 0) vc.width = 32; + vc.height /= 16; + vc.height *= 16; + if (vc.height == 0) vc.height = 16; + + ov511->subx = vc.x; + ov511->suby = vc.y; + ov511->subw = vc.width; + ov511->subh = vc.height; + + return 0; + } case VIDIOCSWIN: { struct video_window vw; @@ -1213,10 +1447,10 @@ struct video_mbuf vm; memset(&vm, 0, sizeof(vm)); - vm.size = MAX_FRAME_SIZE * 2; + vm.size = 2 * MAX_DATA_SIZE; vm.frames = 2; vm.offsets[0] = 0; - vm.offsets[1] = MAX_FRAME_SIZE; + vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval); if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; @@ -1236,7 +1470,8 @@ vm.frame, vm.width, vm.height, vm.format); #endif - if (vm.format != VIDEO_PALETTE_RGB24) + if (vm.format != VIDEO_PALETTE_RGB24 && + vm.format != VIDEO_PALETTE_GREY) return -EINVAL; if ((vm.frame != 0) && (vm.frame != 1)) @@ -1247,18 +1482,27 @@ /* Don't compress if the size changed */ if ((ov511->frame[vm.frame].width != vm.width) || - (ov511->frame[vm.frame].height != vm.height)) { - ov511->compress = 0; + (ov511->frame[vm.frame].height != vm.height) || + (ov511->frame[vm.frame].format != vm.format) || + (ov511->frame[vm.frame].sub_flag != + ov511->sub_flag)) { + /* If we're collecting previous frame wait + before changing modes */ + interruptible_sleep_on(&ov511->wq); + if (signal_pending(current)) return -EINTR; ov511_mode_init_regs(ov511, - vm.width, vm.height, 0); -#if 0 - PDEBUG("ov511: Setting frame %d to (%d, %d) : %d", - vm.frame, vm.width, vm.height, 0); -#endif + vm.width, vm.height, + vm.format, ov511->sub_flag); } ov511->frame[vm.frame].width = vm.width; ov511->frame[vm.frame].height = vm.height; + ov511->frame[vm.frame].format = vm.format; + ov511->frame[vm.frame].sub_flag = ov511->sub_flag; + ov511->frame[vm.frame].segsize = + vm.format == VIDEO_PALETTE_RGB24 ? 384 : 256; + ov511->frame[vm.frame].depth = + vm.format == VIDEO_PALETTE_RGB24 ? 3 : 1; /* Mark it as ready */ ov511->frame[vm.frame].grabstate = FRAME_READY; @@ -1273,7 +1517,8 @@ return -EFAULT; #if 0 - PDEBUG("syncing to frame %d", frame); + PDEBUG("syncing to frame %d, grabstate = %d", frame, + ov511->frame[frame].grabstate); #endif switch (ov511->frame[frame].grabstate) { case FRAME_UNUSED: @@ -1282,6 +1527,9 @@ case FRAME_GRABBING: case FRAME_ERROR: redo: + if (!ov511->dev) + return -EIO; + do { #if 0 init_waitqueue_head(&ov511->frame[frame].wq); @@ -1351,6 +1599,9 @@ if (!dev || !buf) return -EFAULT; + if (!ov511->dev) + return -EIO; + /* See if a frame is completed, then use it. */ if (ov511->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */ frmx = 0; @@ -1376,6 +1627,9 @@ frame = &ov511->frame[frmx]; restart: + if (!ov511->dev) + return -EIO; + while (frame->grabstate == FRAME_GRABBING) { interruptible_sleep_on(&ov511->frame[frmx].wq); if (signal_pending(current)) @@ -1422,9 +1676,12 @@ unsigned long start = (unsigned long)adr; unsigned long page, pos; + if (!ov511->dev) + return -EIO; + PDEBUG("mmap: %ld (%lX) bytes", size, size); - if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) + if (size > (((2 * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) return -EINVAL; pos = (unsigned long)ov511->fbuf; @@ -1444,11 +1701,10 @@ return 0; } -// FIXME - needs V4L ID to be assigned static struct video_device ov511_template = { "OV511 USB Camera", VID_TYPE_CAPTURE, - VID_HARDWARE_CPIA, /* FIXME */ + VID_HARDWARE_OV511, ov511_open, ov511_close, ov511_read, @@ -1471,25 +1727,17 @@ if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, OV7610_I2C_READ_ID) < 0) return -1; - - /* Reset the camera chip */ - if (ov511_i2c_reset(dev) < 0) - return -1; -#if 0 - if(usb_ov511_reg_write(dev, OV511_REG_I2C_CLOCK_PRESCALER, - OV511_I2C_CLOCK_PRESCALER)) - return -1; -#endif - if (ov511_reset(dev, OV511_RESET_NOREGS) < 0) return -1; + if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; + schedule_timeout (1 + 150 * HZ / 1000); + /* Dummy read to sync I2C */ if(ov511_i2c_read(dev, 0x00) < 0) return -1; - - + if((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) != 0x7F) || (ov511_i2c_read(dev, OV7610_REG_ID_LOW) != 0xA2)) { err("Failed to read OV7610 ID. You might not have an OV7610,"); @@ -1504,6 +1752,74 @@ static int ov511_configure(struct usb_ov511 *ov511) { struct usb_device *dev = ov511->dev; + int rc; + + static struct ov511_regvals aRegvalsInit[] = + {{OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f}, + {OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01}, + {OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f}, + {OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01}, + {OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f}, + {OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01}, + {OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d}, + {OV511_DONE_BUS, 0x0, 0x00}, + }; + static struct ov511_regvals aRegvalsNorm[] = + {{OV511_REG_BUS, 0x20, 1}, +#if 1 + {OV511_REG_BUS, 0x52, 0x02}, + {OV511_REG_BUS, 0x52, 0x00}, + {OV511_REG_BUS, 0x31, 0x1f}, /* 0f */ + {OV511_REG_BUS, 0x70, 0x3f}, + {OV511_REG_BUS, 0x71, 0x3f}, + {OV511_REG_BUS, 0x72, 0x01}, + {OV511_REG_BUS, 0x73, 0x01}, + {OV511_REG_BUS, 0x74, 0x01}, + {OV511_REG_BUS, 0x75, 0x01}, + {OV511_REG_BUS, 0x76, 0x01}, + {OV511_REG_BUS, 0x77, 0x01}, + {OV511_REG_BUS, 0x78, 0x06}, + {OV511_REG_BUS, 0x79, 0x03}, + + + {OV511_I2C_BUS, 0x10, 0xff}, + {OV511_I2C_BUS, 0x16, 0x06}, + {OV511_I2C_BUS, 0x28, 0x24}, /* 24 */ + {OV511_I2C_BUS, 0x2b, 0xac}, + {OV511_I2C_BUS, 0x5, 0x00}, + {OV511_I2C_BUS, 0x6, 0x00}, +#if 0 +#endif + {OV511_I2C_BUS, 0x12, 0x00}, + {OV511_I2C_BUS, 0x13, 0x00}, + {OV511_I2C_BUS, 0x38, 0x81}, + {OV511_I2C_BUS, 0x28, 0x24}, /* 0c */ + {OV511_I2C_BUS, 0x05, 0x00}, + {OV511_I2C_BUS, 0x0f, 0x05}, + {OV511_I2C_BUS, 0x15, 0x01}, + {OV511_I2C_BUS, 0x20, 0x1c}, + {OV511_I2C_BUS, 0x23, 0x2a}, + {OV511_I2C_BUS, 0x24, 0x10}, + {OV511_I2C_BUS, 0x25, 0x8a}, + {OV511_I2C_BUS, 0x26, 0x90}, + {OV511_I2C_BUS, 0x27, 0xc2}, + {OV511_I2C_BUS, 0x29, 0x03}, /* 91 */ + {OV511_I2C_BUS, 0x2a, 0x04}, + {OV511_I2C_BUS, 0x2c, 0xfe}, + {OV511_I2C_BUS, 0x2d, 0x93}, /* d7 */ + {OV511_I2C_BUS, 0x30, 0x71}, + {OV511_I2C_BUS, 0x31, 0x60}, + {OV511_I2C_BUS, 0x32, 0x26}, + {OV511_I2C_BUS, 0x33, 0x20}, + {OV511_I2C_BUS, 0x34, 0x48}, + {OV511_I2C_BUS, 0x12, 0x24}, + {OV511_I2C_BUS, 0x13, 0x01}, + {OV511_I2C_BUS, 0x11, 0x01}, + {OV511_I2C_BUS, 0x0c, 0x24}, + {OV511_I2C_BUS, 0x0d, 0x24}, +#endif + {OV511_DONE_BUS, 0x0, 0x00}, + }; /* Set altsetting 0 */ if (usb_set_interface(dev, ov511->iface, 0) < 0) { @@ -1515,25 +1831,15 @@ init_waitqueue_head(&ov511->frame[0].wq); init_waitqueue_head(&ov511->frame[1].wq); + init_waitqueue_head(&ov511->wq); if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) { err("video_register_device failed"); return -EBUSY; } - /* Reset in case driver was unloaded and reloaded without unplug */ - if (ov511_reset(dev, OV511_RESET_ALL) < 0) - goto error; - - /* Initialize system */ - if (ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) { - err("enable system: command failed"); - goto error; - } - - /* This seems to be necessary */ - if (ov511_reset(dev, OV511_RESET_ALL) < 0) - goto error; + if ((rc = ov511_write_regvals(dev, aRegvalsInit))) + return rc; if(ov7610_configure(dev) < 0) { err("failed to configure OV7610"); @@ -1558,7 +1864,10 @@ ov511->frame[1].bytes_read = 0; /* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */ - ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0); + if ((rc = ov511_write_regvals(dev, aRegvalsNorm))) return rc; + if ((rc = ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT, + VIDEO_PALETTE_RGB24, 0)) < 0) return rc; + return 0; @@ -1624,6 +1933,9 @@ case 3: printk("ov511: Camera is a D-Link DSB-C300\n"); break; + case 5: + printk("ov511: Camera is a Puretek PT-6007\n"); + break; case 21: printk("ov511: Camera is a Creative Labs WebCam 3\n"); break; @@ -1661,13 +1973,49 @@ struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr; - video_unregister_device(&ov511->vdev); +// video_unregister_device(&ov511->vdev); + + /* We don't want people trying to open up the device */ + if (!ov511->user) + video_unregister_device(&ov511->vdev); usb_driver_release_interface(&ov511_driver, &ov511->dev->actconfig->interface[ov511->iface]); + ov511->dev = NULL; + ov511->frame[0].grabstate = FRAME_ERROR; + ov511->frame[1].grabstate = FRAME_ERROR; + ov511->curframe = -1; + + /* This will cause the process to request another frame */ + if (waitqueue_active(&ov511->frame[0].wq)) + wake_up_interruptible(&ov511->frame[0].wq); + if (waitqueue_active(&ov511->frame[1].wq)) + wake_up_interruptible(&ov511->frame[1].wq); + if (waitqueue_active(&ov511->wq)) + wake_up_interruptible(&ov511->wq); + + ov511->streaming = 0; + + /* Unschedule all of the iso td's */ + if (ov511->sbuf[1].urb) { + ov511->sbuf[1].urb->next = NULL; + usb_unlink_urb(ov511->sbuf[1].urb); + usb_free_urb(ov511->sbuf[1].urb); + ov511->sbuf[1].urb = NULL; + } + if (ov511->sbuf[0].urb) { + ov511->sbuf[0].urb->next = NULL; + usb_unlink_urb(ov511->sbuf[0].urb); + usb_free_urb(ov511->sbuf[0].urb); + ov511->sbuf[0].urb = NULL; + } + /* Free the memory */ - kfree(ov511); ov511 = NULL; + if (!ov511->user) { + kfree(ov511); + ov511 = NULL; + } } static struct usb_driver ov511_driver = { diff -u --recursive --new-file v2.3.42/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h --- v2.3.42/linux/drivers/usb/ov511.h Fri Jan 21 18:19:17 2000 +++ linux/drivers/usb/ov511.h Wed Feb 9 11:51:13 2000 @@ -166,7 +166,9 @@ /* Prototypes */ int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg); -int usb_ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value); +int usb_ov511_reg_write(struct usb_device *dev, + unsigned char reg, + unsigned char value); enum { @@ -175,10 +177,6 @@ STATE_LINES, /* Parsing lines */ }; -struct ov511_frame_header { - // FIXME - nothing here yet -}; - struct usb_device; struct ov511_sbuf { @@ -194,17 +192,30 @@ FRAME_ERROR, /* Something bad happened while processing */ }; +struct ov511_regvals { + enum { + OV511_DONE_BUS, + OV511_REG_BUS, + OV511_I2C_BUS, + } bus; + unsigned char reg; + unsigned char val; +}; + struct ov511_frame { char *data; /* Frame buffer */ - struct ov511_frame_header header; /* Header from stream */ - + int depth; /* Bytes per pixel */ int width; /* Width application is expecting */ int height; /* Height */ int hdrwidth; /* Width the frame actually is */ int hdrheight; /* Height */ + int sub_flag; /* Sub-capture mode for this frame? */ + int format; /* Format for this frame */ + int segsize; /* How big is each segment from the camera? */ + volatile int grabstate; /* State of grabbing */ int scanstate; /* State of scanning */ @@ -241,6 +252,12 @@ char *fbuf; /* Videodev buffer area */ + int sub_flag; /* Pix Array subcapture on flag */ + int subx; /* Pix Array subcapture x offset */ + int suby; /* Pix Array subcapture y offset */ + int subw; /* Pix Array subcapture width */ + int subh; /* Pix Array subcapture height */ + int curframe; /* Current receiving sbuf */ struct ov511_frame frame[OV511_NUMFRAMES]; @@ -250,6 +267,8 @@ /* Scratch space from the Isochronous pipe */ unsigned char scratch[SCRATCH_BUF_SIZE]; int scratchlen; + + wait_queue_head_t wq; /* Processes waiting */ }; #endif diff -u --recursive --new-file v2.3.42/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.3.42/linux/drivers/usb/printer.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/printer.c Wed Feb 9 15:20:13 2000 @@ -206,7 +206,6 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { - DECLARE_WAITQUEUE(wait, current); struct usblp *usblp = file->private_data; int retval, timeout, writecount = 0; @@ -267,7 +266,6 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; - DECLARE_WAITQUEUE(wait, current); if (!usblp->bidir) return -EINVAL; @@ -423,7 +421,7 @@ write: usblp_write, open: usblp_open, release: usblp_release, - poll: usblp_poll + poll: usblp_poll, }; static struct usb_driver usblp_driver = { diff -u --recursive --new-file v2.3.42/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c --- v2.3.42/linux/drivers/usb/scanner.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/scanner.c Wed Feb 9 11:42:35 2000 @@ -1,7 +1,7 @@ /* -*- linux-c -*- */ /* - * Driver for USB Scanners (linux-2.3.41) + * Driver for USB Scanners (linux-2.3.42) * * Copyright (C) 1999, 2000 David E. Nelson * @@ -85,7 +85,7 @@ * - Added the HP 5200C USB Vendor/Product ID's. * * - * 0.3.4 + * 0.3.4 1/23/2000 * * - Added Greg K-H's patch for better handling of * Product/Vendor detection. @@ -106,14 +106,34 @@ * - Added some Mustek ID's. Thanks to Gernot Hoyler * . * - Modified the usb_string() reporting. See kfree() comment above. - * - Added Umax Astra 2000U. Thanks to Doug Alcorn. + * - Added Umax Astra 2000U. Thanks to Doug Alcorn . * - Updated the printk()'s to use the info/warn/dbg macros. - * - Updated usb_bulk_msg() argument types to correct gcc warnings. + * - Updated usb_bulk_msg() argument types to fix gcc warnings. + * + * + * 0.4 2/4/2000 + * + * - Removed usb_string() from probe_scanner since the core now does a + * good job of reporting what was connnected. + * - Finally, simultaneous multiple device attachment! + * - Fixed some potential memory freeing issues should memory allocation + * fail in probe_scanner(); + * - Some fixes to disconnect_scanner(). + * - Added interrupt endpoint support. + * - Added Agfa SnapScan Touch. Thanks to Jan Van den Bergh + * . + * - Added Umax 1220U ID's. Thanks to Maciek Klimkowski + * . + * - Fixed bug in write_scanner(). The buffer was not being properly + * updated for writes larger than OBUF_SIZE. Thanks to Henrik + * Johansson for identifying it. + * - Added Microtek X6 ID's. Thanks to Oliver Neukum + * . * * * TODO * - * - Simultaneous multiple device attachment + * - Select/poll methods * * * Thanks to: @@ -131,31 +151,68 @@ * 300 dpi scan of the entire bed * 24 Bit Color ~ 70 secs - 3.6 Mbit/sec * 8 Bit Gray ~ 17 secs - 4.2 Mbit/sec - * */ + */ #include "scanner.h" + +static void +irq_scanner(struct urb *urb) +{ + +/* + * For the meantime, this is just a placeholder until I figure out what + * all I want to do with it. + */ + + struct scn_usb_data *scn = urb->context; + unsigned char *data = &scn->button; + + if (urb->status) { + return; + } + + dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data); + return; +} + + static int open_scanner(struct inode * inode, struct file * file) { - struct hpscan_usb_data *hps = &hpscan; + struct scn_usb_data *scn; struct usb_device *dev; - dev = hps->hpscan_dev; + kdev_t scn_minor; + + scn_minor = USB_SCN_MINOR(inode); + + dbg("open_scanner: scn_minor:%d", scn_minor); + + if (!p_scn_table[scn_minor]) { + err("open_scanner(%d): invalid scn_minor", scn_minor); + return -ENOIOCTLCMD; + } + + scn = p_scn_table[scn_minor]; + + dev = scn->scn_dev; if (!dev) { return -ENODEV; } - if (!hps->present) { + if (!scn->present) { return -ENODEV; } - if (hps->isopen) { + if (scn->isopen) { return -EBUSY; } - hps->isopen = 1; + scn->isopen = 1; + + file->private_data = scn; /* Used by the read and write metheds */ MOD_INC_USE_COUNT; @@ -165,9 +222,24 @@ static int close_scanner(struct inode * inode, struct file * file) { - struct hpscan_usb_data *hps = &hpscan; + struct scn_usb_data *scn; - hps->isopen = 0; + kdev_t scn_minor; + + scn_minor = USB_SCN_MINOR (inode); + + dbg("close_scanner: scn_minor:%d", scn_minor); + + if (!p_scn_table[scn_minor]) { + err("close_scanner(%d): invalid scn_minor", scn_minor); + return -ENOIOCTLCMD; + } + + scn = p_scn_table[scn_minor]; + + scn->isopen = 0; + + file->private_data = NULL; MOD_DEC_USE_COUNT; @@ -178,7 +250,7 @@ write_scanner(struct file * file, const char * buffer, size_t count, loff_t *ppos) { - struct hpscan_usb_data *hps = &hpscan; + struct scn_usb_data *scn; struct usb_device *dev; ssize_t bytes_written = 0; @@ -188,9 +260,13 @@ int partial; int result = 0; - char *obuf = hps->obuf; + char *obuf; + + scn = file->private_data; + + obuf = scn->obuf; - dev = hps->hpscan_dev; + dev = scn->scn_dev; while (count > 0) { @@ -201,20 +277,20 @@ copy_size = (count > OBUF_SIZE) ? OBUF_SIZE : count; - if (copy_from_user(hps->obuf, buffer, copy_size)) { + if (copy_from_user(scn->obuf, buffer, copy_size)) { ret = -EFAULT; break; } - result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, hps->bulk_out_ep), obuf, copy_size, &partial, 60*HZ); - dbg("write stats: result:%d copy_size:%d partial:%d", result, copy_size, partial); + result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, copy_size, &partial, 60*HZ); + dbg("write stats(%d): result:%d copy_size:%d partial:%d", scn->scn_minor, result, copy_size, partial); if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */ warn("write_scanner: NAK recieved."); ret = -ETIME; break; } else if (result < 0) { /* We should not get any I/O errors */ - warn("write_scanner: funky result: %d. Please notify the maintainer.", result); + warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn->scn_minor, result); ret = -EIO; break; } @@ -223,7 +299,7 @@ if (partial) { unsigned char cnt, cnt_max; cnt_max = (partial > 24) ? 24 : partial; - printk(KERN_DEBUG "dump: "); + printk(KERN_DEBUG "dump(%d): ", scn->scn_minor); for (cnt=0; cnt < cnt_max; cnt++) { printk("%X ", obuf[cnt]); } @@ -236,7 +312,7 @@ } if (partial) { /* Data written */ - obuf += partial; + buffer += partial; count -= partial; bytes_written += partial; } else { /* No data written */ @@ -245,7 +321,7 @@ break; } } - mdelay(5); + mdelay(5); /* This seems to help with SANE queries */ return ret ? ret : bytes_written; } @@ -253,7 +329,7 @@ read_scanner(struct file * file, char * buffer, size_t count, loff_t *ppos) { - struct hpscan_usb_data *hps = &hpscan; + struct scn_usb_data *scn; struct usb_device *dev; ssize_t read_count, ret = 0; @@ -262,9 +338,13 @@ int this_read; int result; - char *ibuf = hps->ibuf; + char *ibuf; - dev = hps->hpscan_dev; + scn = file->private_data; + + ibuf = scn->ibuf; + + dev = scn->scn_dev; read_count = 0; @@ -276,15 +356,15 @@ this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count; - result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, hps->bulk_in_ep), ibuf, this_read, &partial, 60*HZ); - dbg("read stats: result:%d this_read:%d partial:%d", result, this_read, partial); + result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, 60*HZ); + dbg("read stats(%d): result:%d this_read:%d partial:%d", scn->scn_minor, result, this_read, partial); if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */ - warn("read_scanner: NAK received"); + warn("read_scanner(%d): NAK received", scn->scn_minor); ret = -ETIME; break; } else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) { - warn("read_scanner: funky result: %d. Please notify the maintainer.", (int)result); + warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn->scn_minor, (int)result); ret = -EIO; break; } @@ -293,7 +373,7 @@ if (partial) { unsigned char cnt, cnt_max; cnt_max = (partial > 24) ? 24 : partial; - printk(KERN_DEBUG "dump: "); + printk(KERN_DEBUG "dump(%d): ", scn->scn_minor); for (cnt=0; cnt < cnt_max; cnt++) { printk("%X ", ibuf[cnt]); } @@ -325,21 +405,24 @@ static void * probe_scanner(struct usb_device *dev, unsigned int ifnum) { - struct hpscan_usb_data *hps = &hpscan; + struct scn_usb_data *scn; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; int ep_cnt; + kdev_t scn_minor; + char valid_device = 0; char have_bulk_in, have_bulk_out, have_intr; - hps->present = 0; - if (vendor != -1 && product != -1) { info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product); } + dbg("probe_scanner: USB dev address:%p", dev); + dbg("probe_scanner: ifnum:%u", ifnum); + /* * 1. Check Vendor/Product * 2. Determine/Assign Bulk Endpoints @@ -375,16 +458,20 @@ } } - if (dev->descriptor.idVendor == 0x06bd && /* AGFA */ - dev->descriptor.idProduct == 0x0001) { /* SnapScan 1212U */ - valid_device = 1; - break; + if (dev->descriptor.idVendor == 0x06bd) { /* Agfa */ + if (dev->descriptor.idProduct == 0x0001 || /* SnapScan 1212U */ + dev->descriptor.idProduct == 0x0100) { /* SnapScan Touch */ + valid_device = 1; + break; + } } - if (dev->descriptor.idVendor == 0x1606 && /* Umax */ - dev->descriptor.idProduct == 0x0030) { /* Astra 2000U */ - valid_device = 1; - break; + if (dev->descriptor.idVendor == 0x1606) { /* Umax */ + if (dev->descriptor.idProduct == 0x0010 || /* Astra 1220U */ + dev->descriptor.idProduct == 0x0030) { /* Astra 2000U */ + valid_device = 1; + break; + } } if (dev->descriptor.idVendor == 0x04b8) { /* Seiko/Epson Corp. */ @@ -402,15 +489,24 @@ } } + if (dev->descriptor.idVendor == 0x05da) { /* Microtek */ + if (dev->descriptor.idProduct == 0x0099) { /* X6 */ + valid_device = 1; + break; + } + } + if (dev->descriptor.idVendor == vendor && /* User specified */ dev->descriptor.idProduct == product) { /* User specified */ valid_device = 1; break; } + + } while (0); - if (!valid_device) - return NULL; + if (!valid_device) + return NULL; /* We didn't find anything pleasing */ /* @@ -419,17 +515,17 @@ */ if (dev->descriptor.bNumConfigurations != 1) { - info("probe_scanner: Only one configuration is supported."); + info("probe_scanner: Only one device configuration is supported."); return NULL; } if (dev->config[0].bNumInterfaces != 1) { - info("probe_scanner: Only one interface is supported."); + info("probe_scanner: Only one device interface is supported."); return NULL; } - interface = dev->config[0].interface[0].altsetting; - endpoint = interface[0].endpoint; + interface = dev->config[0].interface[ifnum].altsetting; + endpoint = interface[ifnum].endpoint; /* * Start checking for two bulk endpoints OR two bulk endpoints *and* one @@ -437,8 +533,7 @@ * setup the handler. FIXME: This is a future enhancement... */ - - dbg("probe_scanner: Number of Endpoints: %d", (int) interface->bNumEndpoints); + dbg("probe_scanner: Number of Endpoints:%d", (int) interface->bNumEndpoints); if ((interface->bNumEndpoints != 2) && (interface->bNumEndpoints != 3)) { info("probe_scanner: Only two or three endpoints supported."); @@ -450,32 +545,35 @@ while (ep_cnt < interface->bNumEndpoints) { if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) { - have_bulk_in = 1; - hps->bulk_in_ep = ep_cnt + 1; ep_cnt++; - dbg("probe_scanner: bulk_in_ep: %d", (int)hps->bulk_in_ep); + have_bulk_in = ep_cnt; + dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in); continue; } if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) { - have_bulk_out = 1; - hps->bulk_out_ep = ep_cnt + 1; ep_cnt++; - dbg("probe_scanner: bulk_out_ep: %d", (int)hps->bulk_out_ep); + have_bulk_out = ep_cnt; + dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out); continue; } if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) { - have_intr = 1; - hps->intr_ep = ep_cnt + 1; ep_cnt++; - dbg("probe_scanner: intr_ep: %d", (int)hps->intr_ep); + have_intr = ep_cnt; + dbg("probe_scanner: intr_ep:%d", have_intr); continue; } info("probe_scanner: Undetected endpoint. Notify the maintainer."); return NULL; /* Shouldn't ever get here unless we have something weird */ } + +/* + * Perform a quick check to make sure that everything worked as it + * should have. + */ + switch(interface->bNumEndpoints) { case 2: if (!have_bulk_in || !have_bulk_out) { @@ -494,53 +592,124 @@ return NULL; } - hps->present = 1; - hps->hpscan_dev = dev; - if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) { +/* + * Determine a minor number and initialize the structure associated + * with it. The problem with this is that we are counting on the fact + * that the user will sequentially add device nodes for the scanner + * devices. */ + + for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) { + if (!p_scn_table[scn_minor]) + break; + } + +/* Check to make sure that the last slot isn't already taken */ + if (p_scn_table[scn_minor]) { + err("probe_scanner: No more minor devices remaining."); + return NULL; + } + + dbg("probe_scanner: Allocated minor:%d", scn_minor); + + if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) { + err("probe_scanner: Out of memory."); + return NULL; + } + memset (scn, 0, sizeof(struct scn_usb_data)); + dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn); + + +/* Ok, if we detected an interrupt EP, setup a handler for it */ + if (have_intr) { + dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr); + FILL_INT_URB(&scn->scn_irq, dev, + usb_rcvintpipe(dev, have_intr), + &scn->button, 1, irq_scanner, scn, + // endpoint[(int)have_intr].bInterval); + 250); + + if (usb_submit_urb(&scn->scn_irq)) { + err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor); + kfree(scn); + return NULL; + } + } + + +/* Ok, now initialize all the relevant values */ + if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) { + err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor); + kfree(scn); return NULL; } + dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf); - if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) { + if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) { + err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor); + kfree(scn->obuf); + kfree(scn); return NULL; } + dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf); - return hps; + scn->bulk_in_ep = have_bulk_in; + scn->bulk_out_ep = have_bulk_out; + scn->intr_ep = have_intr; + scn->present = 1; + scn->scn_dev = dev; + scn->scn_minor = scn_minor; + scn->isopen = 0; + + return p_scn_table[scn_minor] = scn; } static void disconnect_scanner(struct usb_device *dev, void *ptr) { - struct hpscan_usb_data *hps = (struct hpscan_usb_data *) ptr; - - if (hps->isopen) { - /* better let it finish - the release will do whats needed */ - hps->hpscan_dev = NULL; - return; - } - kfree(hps->ibuf); - kfree(hps->obuf); - - hps->present = 0; + struct scn_usb_data *scn = (struct scn_usb_data *) ptr; + + if(scn->intr_ep) { + dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor); + usb_unlink_urb(&scn->scn_irq); + } + usb_driver_release_interface(&scanner_driver, + &scn->scn_dev->actconfig->interface[scn->ifnum]); + + kfree(scn->ibuf); + kfree(scn->obuf); + + dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor); + p_scn_table[scn->scn_minor] = NULL; + kfree (scn); } static int ioctl_scanner(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct hpscan_usb_data *hps = &hpscan; struct usb_device *dev; - + int result; + + kdev_t scn_minor; - dev = hps->hpscan_dev; + scn_minor = USB_SCN_MINOR(inode); + + if (!p_scn_table[scn_minor]) { + err("ioctl_scanner(%d): invalid scn_minor", scn_minor); + return -ENOIOCTLCMD; + } + dev = p_scn_table[scn_minor]->scn_dev; + switch (cmd) { - case PV8630_RECEIVE : + case PV8630_IOCTL_INREQUEST : { struct { - unsigned char data; + __u8 data; + __u8 request; __u16 value; __u16 index; } args; @@ -548,23 +717,25 @@ if (copy_from_user(&args, (void *)arg, sizeof(args))) return -EFAULT; - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x0, - USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN, - args.value, args.index, &args.data, 1, HZ); + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + args.request, USB_TYPE_VENDOR| + USB_RECIP_DEVICE|USB_DIR_IN, + args.value, args.index, &args.data, + 1, HZ*5); - dbg("ioctl_scanner recv: args.data:%x args.value:%x args.index:%x", - args.data, args.value, args.index); + dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request); if (copy_to_user((void *)arg, &args, sizeof(args))) return -EFAULT; - - dbg("ioctl_scanner recv: result:%d", result); + dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result); + return result; } - case PV8630_SEND : + case PV8630_IOCTL_OUTREQUEST : { struct { + __u8 request; __u16 value; __u16 index; } args; @@ -572,15 +743,16 @@ if (copy_from_user(&args, (void *)arg, sizeof(args))) return -EFAULT; - dbg("ioctl_scanner send: args.value:%x args.index:%x", args.value, args.index); + dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x1 /* Vendor Specific bRequest */, - USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_OUT /* 0x40 */, - args.value, args.index, NULL, 0, HZ); + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + args.request, USB_TYPE_VENDOR| + USB_RECIP_DEVICE|USB_DIR_OUT, + args.value, args.index, NULL, + 0, HZ*5); - dbg("ioctl_scanner send: result:%d", result); + dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result); - return result; } default: @@ -591,18 +763,11 @@ static struct file_operations usb_scanner_fops = { - NULL, /* seek */ - read_scanner, - write_scanner, - NULL, /* readdir */ - NULL, /* poll */ - ioctl_scanner, /* ioctl */ - NULL, /* mmap */ - open_scanner, - NULL, /* flush */ - close_scanner, - NULL, - NULL, /* fasync */ + read: read_scanner, + write: write_scanner, + ioctl: ioctl_scanner, + open: open_scanner, + release: close_scanner, }; static struct @@ -612,7 +777,7 @@ disconnect_scanner, { NULL, NULL }, &usb_scanner_fops, - 48 + SCN_BASE_MNR }; int @@ -625,16 +790,6 @@ return 0; } - -void -usb_scanner_cleanup(void) -{ - struct hpscan_usb_data *hps = &hpscan; - - hps->present = 0; - usb_deregister(&scanner_driver); -} - #ifdef MODULE int @@ -646,7 +801,7 @@ void cleanup_module(void) { - usb_scanner_cleanup(); + usb_deregister(&scanner_driver); } #endif diff -u --recursive --new-file v2.3.42/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h --- v2.3.42/linux/drivers/usb/scanner.h Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/scanner.h Mon Feb 7 19:13:45 2000 @@ -18,6 +18,8 @@ #define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) #define IS_EP_INTR(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0) +#define USB_SCN_MINOR(X) MINOR((X)->i_rdev) - SCN_BASE_MNR + #ifdef DEBUG #define SCN_DEBUG(X) X #else @@ -30,19 +32,25 @@ /* FIXME: These are NOT registered ioctls()'s */ -#define PV8630_RECEIVE 69 -#define PV8630_SEND 70 +#define PV8630_IOCTL_INREQUEST 69 +#define PV8630_IOCTL_OUTREQUEST 70 + +#define SCN_MAX_MNR 16 /* We're allocated 16 minors */ +#define SCN_BASE_MNR 48 /* USB Scanners start at minor 48 */ -struct hpscan_usb_data { - struct usb_device *hpscan_dev; - int isopen; /* Not zero if the device is open */ - int present; /* Device is present on the bus */ +struct scn_usb_data { + struct usb_device *scn_dev; + struct urb scn_irq; + unsigned int ifnum; /* Interface number of the USB device */ + kdev_t scn_minor; /* Scanner minor - used in disconnect() */ + unsigned char button; /* Front panel buffer */ + char isopen; /* Not zero if the device is open */ + char present; /* Not zero if device is present */ char *obuf, *ibuf; /* transfer buffers */ char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */ - char *button; /* Front panel button buffer */ }; -static struct hpscan_usb_data hpscan; +static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */}; MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson"); MODULE_DESCRIPTION("USB Scanner Driver"); @@ -53,3 +61,6 @@ MODULE_PARM(product, "i"); MODULE_PARM_DESC(product, "User specified USB idProduct"); + +/* Forward declarations */ +static struct usb_driver scanner_driver; diff -u --recursive --new-file v2.3.42/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.42/linux/drivers/usb/uhci.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/uhci.c Tue Feb 8 17:11:13 2000 @@ -46,10 +46,8 @@ #include "uhci.h" #include "uhci-debug.h" -#ifdef CONFIG_APM -#include -static int handle_apm_event(apm_event_t event); -#endif +#include +static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data); static int debug = 1; MODULE_PARM(debug, "i"); @@ -61,53 +59,41 @@ static int rh_submit_urb(urb_t *urb); static int rh_unlink_urb(urb_t *urb); -static int uhci_get_current_frame_number(struct usb_device *usb_dev); +static int uhci_get_current_frame_number(struct usb_device *dev); +static void uhci_stop_hc_schedule(struct uhci *uhci); +static void uhci_start_hc_schedule(struct uhci *uhci); +static int uhci_unlink_urb(urb_t *urb); #define min(a,b) (((a)<(b))?(a):(b)) /* * Only the USB core should call uhci_alloc_dev and uhci_free_dev */ -static int uhci_alloc_dev(struct usb_device *usb_dev) +static int uhci_alloc_dev(struct usb_device *dev) { - struct uhci_device *dev; - - /* Allocate the UHCI device private data */ - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -1; - - /* Initialize "dev" */ - memset(dev, 0, sizeof(*dev)); - - usb_dev->hcpriv = dev; - dev->usb = usb_dev; - atomic_set(&dev->refcnt, 1); - - if (usb_dev->parent) - dev->uhci = usb_to_uhci(usb_dev->parent)->uhci; - return 0; } -static int uhci_free_dev(struct usb_device *usb_dev) +static int uhci_free_dev(struct usb_device *dev) { - struct uhci_device *dev = usb_to_uhci(usb_dev); - - if (atomic_dec_and_test(&dev->refcnt)) - kfree(dev); + urb_t *u; + struct uhci *uhci = (struct uhci *)dev->bus->hcpriv; + struct list_head *tmp, *head = &uhci->urb_list; + unsigned long flags; - return 0; -} + /* Walk through the entire URB list and forcefully remove any */ + /* URBs that are still active for that device */ + nested_lock(&uhci->urblist_lock, flags); + tmp = head->next; + while (tmp != head) { + u = list_entry(tmp, urb_t, urb_list); -static void uhci_inc_dev_use(struct uhci_device *dev) -{ - atomic_inc(&dev->refcnt); -} + if (u->dev == dev) + uhci_unlink_urb(u); + } + nested_unlock(&uhci->urblist_lock, flags); -static void uhci_dec_dev_use(struct uhci_device *dev) -{ - uhci_free_dev(dev->usb); + return 0; } /* @@ -138,21 +124,21 @@ { unsigned long flags; - spin_lock_irqsave(&uhci->urblist_lock, flags); + nested_lock(&uhci->urblist_lock, flags); list_add(&urb->urb_list, &uhci->urb_list); - spin_unlock_irqrestore(&uhci->urblist_lock, flags); + nested_unlock(&uhci->urblist_lock, flags); } static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb) { unsigned long flags; - spin_lock_irqsave(&uhci->urblist_lock, flags); + nested_lock(&uhci->urblist_lock, flags); if (urb->urb_list.next != &urb->urb_list) { list_del(&urb->urb_list); INIT_LIST_HEAD(&urb->urb_list); } - spin_unlock_irqrestore(&uhci->urblist_lock, flags); + nested_unlock(&uhci->urblist_lock, flags); } /* @@ -255,7 +241,7 @@ prevtd->link = UHCI_PTR_TERM; } -static struct uhci_td *uhci_td_alloc(struct uhci_device *dev) +static struct uhci_td *uhci_alloc_td(struct usb_device *dev) { struct uhci_td *td; @@ -273,33 +259,20 @@ INIT_LIST_HEAD(&td->irq_list); INIT_LIST_HEAD(&td->list); - uhci_inc_dev_use(dev); + usb_inc_dev_use(dev); return td; } -static void uhci_td_free(struct uhci_td *td) +static void uhci_free_td(struct uhci_td *td) { kmem_cache_free(uhci_td_cachep, td); if (td->dev) - uhci_dec_dev_use(td->dev); + usb_dec_dev_use(td->dev); } -static void uhci_schedule_delete_td(struct uhci *uhci, struct uhci_td *td) -{ - unsigned long flags; - - spin_lock_irqsave(&uhci->freelist_lock, flags); - list_add(&td->list, &uhci->td_free_list); - if (td->dev) { - uhci_dec_dev_use(td->dev); - td->dev = NULL; - } - spin_unlock_irqrestore(&uhci->freelist_lock, flags); -} - -static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev) +static struct uhci_qh *uhci_alloc_qh(struct usb_device *dev) { struct uhci_qh *qh; @@ -315,30 +288,17 @@ INIT_LIST_HEAD(&qh->list); - uhci_inc_dev_use(dev); + usb_inc_dev_use(dev); return qh; } -static void uhci_qh_free(struct uhci_qh *qh) +static void uhci_free_qh(struct uhci_qh *qh) { kmem_cache_free(uhci_qh_cachep, qh); if (qh->dev) - uhci_dec_dev_use(qh->dev); -} - -static void uhci_schedule_delete_qh(struct uhci *uhci, struct uhci_qh *qh) -{ - unsigned long flags; - - spin_lock_irqsave(&uhci->freelist_lock, flags); - list_add(&qh->list, &uhci->qh_free_list); - if (qh->dev) { - uhci_dec_dev_use(qh->dev); - qh->dev = NULL; - } - spin_unlock_irqrestore(&uhci->freelist_lock, flags); + usb_dec_dev_use(qh->dev); } static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh) @@ -398,6 +358,30 @@ urbp->begin = td; } +void uhci_inc_fsbr(struct uhci *uhci) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->framelist_lock, flags); + + if (!uhci->fsbr++) + uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH; + + spin_unlock_irqrestore(&uhci->framelist_lock, flags); +} + +void uhci_dec_fsbr(struct uhci *uhci) +{ + unsigned long flags; + + spin_lock_irqsave(&uhci->framelist_lock, flags); + + if (!--uhci->fsbr) + uhci->skel_term_qh.link = UHCI_PTR_TERM; + + spin_unlock_irqrestore(&uhci->framelist_lock, flags); +} + /* * Map status to standard result codes * @@ -438,8 +422,7 @@ struct uhci_td *td; struct uhci_qh *qh; unsigned long destination, status; - struct uhci_device *dev = usb_to_uhci(urb->dev); - struct uhci *uhci = dev->uhci; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); int len = urb->transfer_buffer_length; unsigned char *data = urb->transfer_buffer; @@ -462,7 +445,7 @@ /* * Build the TD for the control request */ - td = uhci_td_alloc(dev); + td = uhci_alloc_td(urb->dev); if (!td) return -ENOMEM; @@ -482,7 +465,7 @@ /* * Build the DATA TD's */ - td = uhci_td_alloc(dev); + td = uhci_alloc_td(urb->dev); if (!td) { /* FIXME: Free the TD's */ return -ENOMEM; @@ -504,7 +487,7 @@ data += pktsze; len -= pktsze; - td = uhci_td_alloc(dev); + td = uhci_alloc_td(urb->dev); if (!td) /* FIXME: Free all of the previously allocated td's */ return -ENOMEM; @@ -532,14 +515,19 @@ uhci_add_irq_list(uhci, td); - qh = uhci_qh_alloc(dev); + qh = uhci_alloc_qh(urb->dev); if (!qh) { /* FIXME: Free all of the TD's */ return -ENOMEM; } uhci_insert_tds_in_qh(qh, urbp->begin); - uhci_insert_qh(uhci, &uhci->skel_control_qh, qh); + if (!(urb->pipe & TD_CTRL_LS)) { + uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh); + uhci_inc_fsbr(uhci); + } else + uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh); + urbp->qh = qh; uhci_add_urb_list(uhci, urb); @@ -549,18 +537,27 @@ return -EINPROGRESS; } +/* This is also the uhci_unlink_bulk function */ static int uhci_unlink_control(urb_t *urb) { struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; - struct uhci_device *dev = usb_to_uhci(urb->dev); - struct uhci *uhci = dev->uhci; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + int notfinished; if (!urbp) return -EINVAL; + notfinished = (urb->status == -EINPROGRESS); + + if (notfinished) + uhci_stop_hc_schedule(uhci); + + if (!(urb->pipe & TD_CTRL_LS)) + uhci_dec_fsbr(uhci); + uhci_remove_qh(uhci, urbp->qh); - uhci_schedule_delete_qh(uhci, urbp->qh); + uhci_free_qh(urbp->qh); /* Go through the rest of the TD's, deleting them, then scheduling */ /* their deletion */ @@ -571,11 +568,14 @@ if (td->status & TD_CTRL_IOC) uhci_remove_irq_list(uhci, td); - uhci_schedule_delete_td(uhci, td); + uhci_free_td(td); td = next; } + if (notfinished) + uhci_start_hc_schedule(uhci); + kfree(urbp); urb->hcpriv = NULL; @@ -589,7 +589,6 @@ struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; unsigned int status; - int ret; td = urbp->begin; if (!td) /* Nothing to do */ @@ -617,8 +616,9 @@ /* If SPD is set then we received a short packet */ /* There will be no status phase at the end */ + /* FIXME: Re-setup the queue to run the STATUS phase? */ if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info))) - goto td_success; + return 0; if (status) goto td_error; @@ -635,7 +635,7 @@ if (td->status & TD_CTRL_IOC && status & TD_CTRL_ACTIVE && status & TD_CTRL_NAK) - goto td_success; + return 0; if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; @@ -643,9 +643,6 @@ if (status) goto td_error; -td_success: - uhci_unlink_control(urb); - return 0; td_error: @@ -662,16 +659,9 @@ /* endpoint has stalled - mark it halted */ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info)); - uhci_unlink_control(urb); - - return -EPIPE; } - ret = uhci_map_status(status, uhci_packetout(td->info)); - - uhci_unlink_control(urb); - - return ret; + return uhci_map_status(status, uhci_packetout(td->info)); } /* @@ -681,8 +671,7 @@ { struct uhci_td *td; unsigned long destination, status; - struct uhci_device *dev = usb_to_uhci(urb->dev); - struct uhci *uhci = dev->uhci; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; struct urb_priv *urbp; if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))) @@ -702,7 +691,7 @@ urb->hcpriv = urbp; - td = uhci_td_alloc(dev); + td = uhci_alloc_td(urb->dev); if (!td) return -ENOMEM; @@ -728,17 +717,25 @@ { struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; - struct uhci_device *dev = usb_to_uhci(urb->dev); - struct uhci *uhci = dev->uhci; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + int notfinished; if (!urbp) return -EINVAL; + notfinished = (urb->status == -EINPROGRESS); + + if (notfinished) + uhci_stop_hc_schedule(uhci); + td = urbp->begin; uhci_remove_td(uhci, td); if (td->status & TD_CTRL_IOC) uhci_remove_irq_list(uhci, td); - uhci_schedule_delete_td(uhci, td); + uhci_free_td(td); + + if (notfinished) + uhci_start_hc_schedule(uhci); kfree(urbp); urb->hcpriv = NULL; @@ -765,12 +762,10 @@ if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; - if (status) - return uhci_map_status(status, uhci_packetout(td->info)); - - urb->actual_length += uhci_actual_length(td->status); + if (!status) + urb->actual_length = uhci_actual_length(td->status); - return 0; + return uhci_map_status(status, uhci_packetout(td->info)); } static void uhci_reset_interrupt(urb_t *urb) @@ -778,17 +773,14 @@ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci_td *td; - if (urb->interval) { - td = urbp->begin; + td = urbp->begin; - usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); - td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; - td->info &= ~(1 << TD_TOKEN_TOGGLE); - td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE); + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; + td->info &= ~(1 << TD_TOKEN_TOGGLE); + td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE); - urb->status = -EINPROGRESS; - } else - uhci_unlink_interrupt(urb); + urb->status = -EINPROGRESS; } /* @@ -799,8 +791,7 @@ struct uhci_td *td; struct uhci_qh *qh; unsigned long destination, status; - struct uhci_device *dev = usb_to_uhci(urb->dev); - struct uhci *uhci = dev->uhci; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); int len = urb->transfer_buffer_length; unsigned char *data = urb->transfer_buffer; @@ -834,7 +825,7 @@ if (pktsze > maxsze) pktsze = maxsze; - td = uhci_td_alloc(dev); + td = uhci_alloc_td(urb->dev); if (!td) { /* FIXME: Free the TD's */ return -ENOMEM; @@ -858,20 +849,22 @@ usb_pipeout(urb->pipe)); } - qh = uhci_qh_alloc(dev); + qh = uhci_alloc_qh(urb->dev); if (!qh) { /* FIXME: Free all of the TD's */ return -ENOMEM; } uhci_insert_tds_in_qh(qh, urbp->begin); - uhci_insert_qh(dev->uhci, &dev->uhci->skel_bulk_qh, qh); + uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh); urbp->qh = qh; uhci_add_urb_list(uhci, urb); usb_inc_dev_use(urb->dev); + uhci_inc_fsbr(uhci); + return -EINPROGRESS; } @@ -900,16 +893,13 @@ uhci_packetout(td->info), uhci_toggle(td->info) ^ 1); - goto td_success; + return 0; } if (status) goto td_error; } -td_success: - uhci_unlink_bulk(urb); - return 0; td_error: @@ -926,7 +916,6 @@ /* endpoint has stalled - mark it halted */ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info), uhci_packetout(td->info)); - return -EPIPE; } return uhci_map_status(status, uhci_packetout(td->info)); @@ -942,7 +931,7 @@ struct list_head *tmp, *head = &uhci->urb_list; unsigned long flags; - spin_lock_irqsave(&uhci->urblist_lock, flags); + nested_lock(&uhci->urblist_lock, flags); tmp = head->next; while (tmp != head) { u = list_entry(tmp, urb_t, urb_list); @@ -956,7 +945,7 @@ } tmp = tmp->next; } - spin_unlock_irqrestore(&uhci->urblist_lock, flags); + nested_unlock(&uhci->urblist_lock, flags); if (last_urb) { *end = (last_urb->start_frame + last_urb->number_of_packets) & 1023; @@ -995,8 +984,7 @@ static int uhci_submit_isochronous(urb_t *urb) { struct uhci_td *td; - struct uhci_device *dev = usb_to_uhci(urb->dev); - struct uhci *uhci = dev->uhci; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; struct urb_priv *urbp; int i, ret, framenum; int status, destination; @@ -1021,7 +1009,7 @@ if (!urb->iso_frame_desc[i].length) continue; - td = uhci_td_alloc(dev); + td = uhci_alloc_td(urb->dev); if (!td) { /* FIXME: Free the TD's */ return -ENOMEM; @@ -1050,12 +1038,17 @@ { struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; - struct uhci_device *dev = usb_to_uhci(urb->dev); - struct uhci *uhci = dev->uhci; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; + int notfinished; if (!urbp) return -EINVAL; + notfinished = (urb->status == -EINPROGRESS); + + if (notfinished) + uhci_stop_hc_schedule(uhci); + /* Go through the rest of the TD's, deleting them, then scheduling */ /* their deletion */ td = urbp->begin; @@ -1066,11 +1059,14 @@ if (td->status & TD_CTRL_IOC) uhci_remove_irq_list(uhci, td); - uhci_schedule_delete_td(uhci, td); + uhci_free_td(td); td = next; } + if (notfinished) + uhci_start_hc_schedule(uhci); + kfree(urbp); urb->hcpriv = NULL; @@ -1090,14 +1086,12 @@ if (!td) /* Nothing to do */ return -EINVAL; - status = uhci_status_bits(td->status); + status = uhci_status_bits(td->status); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; - /* Assume no errors, we'll overwrite this if not */ - urb->status = 0; - urb->actual_length = 0; + for (i = 0, td = urbp->begin; td; i++, td = td->next) { int actlength; @@ -1113,9 +1107,7 @@ } } - uhci_unlink_isochronous(urb); - - return status; + return ret; } static int uhci_submit_urb(urb_t *urb) @@ -1150,11 +1142,8 @@ } urb->status = ret; - if (ret == -EINPROGRESS) { - usb_inc_dev_use(urb->dev); - + if (ret == -EINPROGRESS) return 0; - } return ret; } @@ -1173,13 +1162,8 @@ ret = uhci_result_control(urb); break; case PIPE_INTERRUPT: - /* Interrupts are an exception */ - urb->status = uhci_result_interrupt(urb); - if (urb->status != -EINPROGRESS) { - urb->complete(urb); - uhci_reset_interrupt(urb); - } - return; + ret = uhci_result_interrupt(urb); + break; case PIPE_BULK: ret = uhci_result_bulk(urb); break; @@ -1192,6 +1176,26 @@ if (urb->status == -EINPROGRESS) return; + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + uhci_unlink_control(urb); + break; + case PIPE_INTERRUPT: + /* Interrupts are an exception */ + urb->complete(urb); + if (urb->interval) + uhci_reset_interrupt(urb); + else + uhci_unlink_interrupt(urb); + return; + case PIPE_BULK: + uhci_unlink_bulk(urb); + break; + case PIPE_ISOCHRONOUS: + uhci_unlink_isochronous(urb); + break; + } + if (urb->next) { turb = urb->next; do { @@ -1225,8 +1229,6 @@ if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE)) urb->complete(urb); } - - usb_dec_dev_use(urb->dev); } static int uhci_unlink_urb(urb_t *urb) @@ -1237,6 +1239,9 @@ if (!urb) return -EINVAL; + if (!urb->dev || !urb->dev->bus) + return -ENODEV; + uhci = (struct uhci *)urb->dev->bus->hcpriv; if (usb_pipedevice(urb->pipe) == uhci->rh.devnum) @@ -1261,6 +1266,7 @@ if (urb->complete) urb->complete(urb); +#ifndef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE if (in_interrupt()) { /* wait at least 1 frame */ int errorcount = 10; @@ -1269,12 +1275,11 @@ udelay(1000); } else schedule_timeout(1+1*HZ/1000); +#endif - usb_dec_dev_use(urb->dev); + urb->status = -ENOENT; } - urb->status = -ENOENT; - return ret; } @@ -1283,11 +1288,11 @@ * * returns the current frame number for a USB bus/controller. */ -static int uhci_get_current_frame_number(struct usb_device *usb_dev) +static int uhci_get_current_frame_number(struct usb_device *dev) { - struct uhci_device *dev = (struct uhci_device *)usb_dev->hcpriv; + struct uhci *uhci = (struct uhci *)dev->bus->hcpriv; - return inw(dev->uhci->io_addr + USBFRNUM); + return inw(uhci->io_addr + USBFRNUM); } struct usb_operations uhci_device_operations = { @@ -1393,10 +1398,6 @@ urb->status = USB_ST_NOERROR; if ((data > 0) && (uhci->rh.send != 0)) { -#ifdef DEBUG /* JE */ -static int foo=5; -if (foo--) -#endif dbg("root-hub INT complete: port1: %x port2: %x data: %x", inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data); urb->complete(urb); @@ -1464,8 +1465,7 @@ static int rh_submit_urb(urb_t *urb) { - struct usb_device *usb_dev = urb->dev; - struct uhci *uhci = (struct uhci *)usb_dev->bus->hcpriv; + struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv; unsigned int pipe = urb->pipe; devrequest *cmd = (devrequest *)urb->setup_packet; void *data = urb->transfer_buffer; @@ -1645,67 +1645,6 @@ } /*-------------------------------------------------------------------*/ -/* - * This is just incredibly fragile. The timings must be just - * right, and they aren't really documented very well. - * - * Note the short delay between disabling reset and enabling - * the port.. - */ -static void uhci_reset_port(unsigned int port) -{ - unsigned short status; - - status = inw(port); - outw(status | USBPORTSC_PR, port); /* reset port */ - wait_ms(10); - outw(status & ~USBPORTSC_PR, port); - udelay(50); - - status = inw(port); - outw(status | USBPORTSC_PE, port); /* enable port */ - wait_ms(10); - - status = inw(port); - if (!(status & USBPORTSC_PE)) { - outw(status | USBPORTSC_PE, port); /* one more try at enabling port */ - wait_ms(50); - } - -} - -void uhci_free_pending(struct uhci *uhci) -{ - struct list_head *tmp, *head; - - /* Free all of the pending QH's and TD's */ - head = &uhci->td_free_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - - list_del(&td->list); - INIT_LIST_HEAD(&td->list); - - uhci_td_free(td); - } - - head = &uhci->qh_free_list; - tmp = head->next; - while (tmp != head) { - struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, list); - - tmp = tmp->next; - - list_del(&qh->list); - INIT_LIST_HEAD(&qh->list); - - uhci_qh_free(qh); - } -} - static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) { struct uhci *uhci = __uhci; @@ -1737,11 +1676,6 @@ } } - /* Free all of the pending QH's and TD's */ - spin_lock(&uhci->freelist_lock); - uhci_free_pending(uhci); - spin_unlock(&uhci->freelist_lock); - /* Walk the list of pending TD's to see which ones completed.. */ nested_lock(&uhci->irqlist_lock, flags); head = &uhci->interrupt_list; @@ -1759,6 +1693,40 @@ nested_unlock(&uhci->irqlist_lock, flags); } +static void uhci_stop_hc_schedule(struct uhci *uhci) +{ +#ifdef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE + unsigned int cmdreg, timeout = 1000; + + cmdreg = inw(uhci->io_addr + USBCMD); + outw(cmdreg & ~USBCMD_RS, uhci->io_addr + USBCMD); + + while (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) { + if (!--timeout) { + printk(KERN_ERR "uhci: stop_hc_schedule failed, HC still running\n"); + break; + } + } +#endif +} + +static void uhci_start_hc_schedule(struct uhci *uhci) +{ +#ifdef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE + unsigned int cmdreg, timeout = 1000; + + cmdreg = inw(uhci->io_addr + USBCMD); + outw(cmdreg | USBCMD_RS, uhci->io_addr + USBCMD); + + while (inw(uhci->io_addr + USBSTS) & USBSTS_HCH) { + if (!--timeout) { + printk(KERN_ERR "uhci: start_hc_schedule failed, HC still halted\n"); + break; + } + } +#endif +} + static void reset_hc(struct uhci *uhci) { unsigned int io_addr = uhci->io_addr; @@ -1833,14 +1801,13 @@ INIT_LIST_HEAD(&uhci->interrupt_list); INIT_LIST_HEAD(&uhci->urb_list); - INIT_LIST_HEAD(&uhci->td_free_list); - INIT_LIST_HEAD(&uhci->qh_free_list); - spin_lock_init(&uhci->urblist_lock); spin_lock_init(&uhci->framelist_lock); - spin_lock_init(&uhci->freelist_lock); + nested_init(&uhci->urblist_lock); nested_init(&uhci->irqlist_lock); + uhci->fsbr = 0; + /* We need exactly one page (per UHCI specs), how convenient */ /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */ uhci->fl = (void *)__get_free_page(GFP_KERNEL); @@ -1892,14 +1859,20 @@ uhci_fill_td(&uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0); - uhci->skel_int1_td.link = virt_to_bus(&uhci->skel_control_qh) | UHCI_PTR_QH; + uhci->skel_int1_td.link = virt_to_bus(&uhci->skel_ls_control_qh) | UHCI_PTR_QH; - uhci->skel_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH; - uhci->skel_control_qh.element = UHCI_PTR_TERM; + uhci->skel_ls_control_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH; + uhci->skel_ls_control_qh.element = UHCI_PTR_TERM; - uhci->skel_bulk_qh.link = UHCI_PTR_TERM; + uhci->skel_hs_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH; + uhci->skel_hs_control_qh.element = UHCI_PTR_TERM; + + uhci->skel_bulk_qh.link = virt_to_bus(&uhci->skel_term_qh) | UHCI_PTR_QH; uhci->skel_bulk_qh.element = UHCI_PTR_TERM; + uhci->skel_term_qh.link = UHCI_PTR_TERM; + uhci->skel_term_qh.element = UHCI_PTR_TERM; + /* * Fill the frame list: make all entries point to * the proper interrupt queue. @@ -1970,19 +1943,17 @@ int uhci_start_root_hub(struct uhci *uhci) { - struct usb_device *usb_dev; + struct usb_device *dev; - usb_dev = usb_alloc_dev(NULL, uhci->bus); - if (!usb_dev) + dev = usb_alloc_dev(NULL, uhci->bus); + if (!dev) return -1; - usb_to_uhci(usb_dev)->uhci = uhci; + uhci->bus->root_hub = dev; + usb_connect(dev); - uhci->bus->root_hub = usb_dev; - usb_connect(usb_dev); - - if (usb_new_device(usb_dev) != 0) { - usb_free_dev(usb_dev); + if (usb_new_device(dev) != 0) { + usb_free_dev(dev); return -1; } @@ -1994,7 +1965,7 @@ * If we've successfully found a UHCI, now is the time to increment the * module usage count, and return success.. */ -static int setup_uhci(int irq, unsigned int io_addr, unsigned int io_size) +static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size) { int retval; struct uhci *uhci; @@ -2017,8 +1988,16 @@ if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) { uhci->irq = irq; - if (!uhci_start_root_hub(uhci)) + if (!uhci_start_root_hub(uhci)) { + struct pm_dev *pmdev; + + pmdev = pm_register(PM_PCI_DEV, + PM_PCI_ID(dev), + handle_pm_event); + if (pmdev) + pmdev->data = uhci; return 0; + } } /* Couldn't allocate IRQ if we got here */ @@ -2060,38 +2039,22 @@ continue; } - return setup_uhci(dev->irq, io_addr, io_size); + return setup_uhci(dev, dev->irq, io_addr, io_size); } return -1; } -#ifdef CONFIG_APM -static int handle_apm_event(apm_event_t event) +static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data) { - static int down = 0; - - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - if (down) { - dbg("received extra suspend event"); - break; - } - down = 1; + switch (rqst) { + case PM_SUSPEND: break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - if (!down) { - dbg("received bogus resume event"); - break; - } - down = 0; + case PM_RESUME: break; } return 0; } -#endif int uhci_init(void) { @@ -2139,10 +2102,6 @@ if (retval && uhci_list.next == &uhci_list) goto init_failed; -#ifdef CONFIG_APM - apm_register_callback(&handle_apm_event); -#endif - return 0; init_failed: @@ -2160,8 +2119,6 @@ void uhci_cleanup(void) { struct list_head *next, *tmp, *head = &uhci_list; - int i; - unsigned long flags; tmp = head->next; while (tmp != head) { @@ -2180,11 +2137,6 @@ reset_hc(uhci); release_region(uhci->io_addr, uhci->io_size); - /* Free any outstanding TD's and QH's */ - spin_lock_irqsave(&uhci->freelist_lock, flags); - uhci_free_pending(uhci); - spin_unlock_irqrestore(&uhci->freelist_lock, flags); - release_uhci(uhci); tmp = next; @@ -2205,9 +2157,7 @@ void cleanup_module(void) { -#ifdef CONFIG_APM - apm_unregister_callback(&handle_apm_event); -#endif + pm_unregister_all(handle_pm_event); uhci_cleanup(); } #endif //MODULE diff -u --recursive --new-file v2.3.42/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h --- v2.3.42/linux/drivers/usb/uhci.h Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/uhci.h Tue Feb 8 17:11:13 2000 @@ -108,7 +108,7 @@ /* Software fields */ struct uhci_qh *prevqh, *nextqh; /* Previous and next TD in queue */ - struct uhci_device *dev; /* The owning device */ + struct usb_device *dev; /* The owning device */ struct list_head list; } __attribute__((aligned(16))); @@ -182,7 +182,7 @@ unsigned int *frameptr; /* Frame list pointer */ struct uhci_td *prevtd, *nexttd; /* Previous and next TD in queue */ - struct uhci_device *dev; + struct usb_device *dev; struct urb *urb; /* URB this TD belongs to */ struct uhci_td *next; /* List of chained TD's for an URB */ @@ -191,26 +191,6 @@ } __attribute__((aligned(16))); /* - * Note the alignment requirements of the entries - * - * Each UHCI device has pre-allocated QH and TD entries. - * You can use more than the pre-allocated ones, but I - * don't see you usually needing to. - */ -struct uhci; - -struct uhci_device { - struct usb_device *usb; - - atomic_t refcnt; - - struct uhci *uhci; /* HC this device is connected to */ -}; - -#define uhci_to_usb(uhci) ((uhci)->usb) -#define usb_to_uhci(usb) ((struct uhci_device *)(usb)->hcpriv) - -/* * There are various standard queues. We set up several different * queues for each of the three basic queue types: interrupt, * control, and bulk. @@ -264,9 +244,11 @@ #define skel_int128_td skeltd[7] #define skel_int256_td skeltd[8] -#define UHCI_NUM_SKELQH 2 -#define skel_control_qh skelqh[0] -#define skel_bulk_qh skelqh[1] +#define UHCI_NUM_SKELQH 4 +#define skel_ls_control_qh skelqh[0] +#define skel_hs_control_qh skelqh[1] +#define skel_bulk_qh skelqh[2] +#define skel_term_qh skelqh[3] /* * Search tree for determining where fits in the @@ -340,14 +322,12 @@ struct s_nested_lock irqlist_lock; struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */ - spinlock_t urblist_lock; + struct s_nested_lock urblist_lock; struct list_head urb_list; spinlock_t framelist_lock; - spinlock_t freelist_lock; - struct list_head td_free_list; - struct list_head qh_free_list; + int fsbr; /* Full speed bandwidth reclamation */ struct virt_root_hub rh; /* private data of the virtual root hub */ }; diff -u --recursive --new-file v2.3.42/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.3.42/linux/drivers/usb/usb-ohci.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/usb-ohci.c Wed Feb 9 19:43:57 2000 @@ -52,10 +52,8 @@ #include "usb.h" #include "usb-ohci.h" -#ifdef CONFIG_APM -#include -static int handle_apm_event (apm_event_t event); -#endif +#include +static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data); #ifdef CONFIG_PMAC_PBOOK #include @@ -1632,7 +1630,7 @@ /* Increment the module usage count, start the control thread and * return success. */ -static int hc_found_ohci (int irq, void * mem_base) +static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base) { ohci_t * ohci; dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base); @@ -1651,8 +1649,17 @@ usb_register_bus (ohci->bus); if (request_irq (irq, hc_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) { + struct pm_dev *pmdev; + ohci->irq = irq; hc_start (ohci); + + pmdev = pm_register (PM_PCI_DEV, + PM_PCI_ID(dev), + handle_pm_event); + if (pmdev) + pmdev->data = ohci; + return 0; } err("request interrupt %d failed", irq); @@ -1664,6 +1671,7 @@ static int hc_start_ohci (struct pci_dev * dev) { + u32 cmd; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) unsigned long mem_base = dev->resource[0].start; #else @@ -1672,6 +1680,11 @@ mem_base &= PCI_BASE_ADDRESS_MEM_MASK; #endif + /* Some Mac firmware will switch memory response off */ + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY); + pci_write_config_dword(dev, PCI_COMMAND, cmd); + pci_set_master (dev); mem_base = (unsigned long) ioremap_nocache (mem_base, 4096); @@ -1679,7 +1692,7 @@ err("Error mapping OHCI memory"); return -EFAULT; } - return hc_found_ohci (dev->irq, (void *) mem_base); + return hc_found_ohci (dev, dev->irq, (void *) mem_base); } /*-------------------------------------------------------------------------*/ @@ -1721,50 +1734,26 @@ /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_APM -static int handle_apm_event (apm_event_t event) +static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data) { - static int down = 0; - ohci_t * ohci; - struct list_head * ohci_l; - - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - if (down) { - dbg("received extra suspend event"); - break; - } - for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) { - ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list); + ohci_t * ohci = (ohci_t*) dev->data; + if (ohci) { + switch (rqst) { + case PM_SUSPEND: dbg("USB-Bus suspend: %p", ohci); writel (ohci->hc_control = 0xFF, &ohci->regs->control); - } - wait_ms (10); - down = 1; - break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - if (!down) { - dbg("received bogus resume event"); + wait_ms (10); break; - } - for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) { - ohci = list_entry(ohci_l, ohci_t, ohci_hcd_list); + case PM_RESUME: dbg("USB-Bus resume: %p", ohci); writel (ohci->hc_control = 0x7F, &ohci->regs->control); - } - wait_ms (20); - for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) { - ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list); + wait_ms (20); writel (ohci->hc_control = 0xBF, &ohci->regs->control); + break; } - down = 0; - break; } return 0; } -#endif /*-------------------------------------------------------------------------*/ @@ -1779,10 +1768,6 @@ if (hc_start_ohci(dev) >= 0) ret = 0; } -#ifdef CONFIG_APM - apm_register_callback (&handle_apm_event); -#endif - #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier (&ohci_sleep_notifier); #endif @@ -1803,9 +1788,7 @@ { ohci_t * ohci; -#ifdef CONFIG_APM - apm_unregister_callback (&handle_apm_event); -#endif + pm_unregister_all (handle_pm_event); #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier (&ohci_sleep_notifier); diff -u --recursive --new-file v2.3.42/linux/drivers/usb/usb-serial.c linux/drivers/usb/usb-serial.c --- v2.3.42/linux/drivers/usb/usb-serial.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/usb-serial.c Mon Feb 7 19:14:42 2000 @@ -14,6 +14,17 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (02/05/2000) gkh + * Added initial framework for the Keyspan PDA serial converter so that + * Brian Warner has a place to put his code. + * Made the ezusb specific functions generic enough that different + * devices can use them (whiteheat and keyspan_pda both need them). + * Split out a whole bunch of structure and other stuff to a seperate + * usb-serial.h file. + * Made the Visor connection messages a little more understandable, now + * that Miles Lott (milos@insync.net) has gotten the Generic channel to + * work. Also made them always show up in the log file. + * * (01/25/2000) gkh * Added initial framework for FTDI serial converter so that Bill Ryder * has a place to put his code. @@ -138,385 +149,12 @@ #include "whiteheat.h" /* firmware for the ConnectTech WhiteHEAT device */ #endif -/* Module information */ -MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"); -MODULE_DESCRIPTION("USB Serial Driver"); - -#ifdef CONFIG_USB_SERIAL_GENERIC -static __u16 vendor = 0x05f9; -static __u16 product = 0xffff; -MODULE_PARM(vendor, "i"); -MODULE_PARM_DESC(vendor, "User specified USB idVendor"); - -MODULE_PARM(product, "i"); -MODULE_PARM_DESC(product, "User specified USB idProduct"); -#endif +#include "usb-serial.h" static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum); static void usb_serial_disconnect(struct usb_device *dev, void *ptr); - -/* USB Serial devices vendor ids and device ids that this driver supports */ -#define BELKIN_VENDOR_ID 0x056c -#define BELKIN_SERIAL_CONVERTER_ID 0x8007 -#define PERACOM_VENDOR_ID 0x0565 -#define PERACOM_SERIAL_CONVERTER_ID 0x0001 -#define CONNECT_TECH_VENDOR_ID 0x0710 -#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 -#define CONNECT_TECH_WHITE_HEAT_ID 0x8001 -#define HANDSPRING_VENDOR_ID 0x082d -#define HANDSPRING_VISOR_ID 0x0100 -#define FTDI_VENDOR_ID 0x0403 -#define FTDI_SERIAL_CONVERTER_ID 0x8372 - -#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ -#define SERIAL_TTY_MINORS 16 /* Actually we are allowed 255, but this is good for now */ - - -#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ - -struct usb_serial { - struct usb_device * dev; - struct usb_serial_device_type * type; - void * irq_handle; - unsigned int irqpipe; - struct tty_struct * tty; /* the coresponding tty for this device */ - unsigned char minor; - unsigned char num_ports; /* the number of ports this device has */ - char active[MAX_NUM_PORTS]; /* someone has this device open */ - - char num_interrupt_in; /* number of interrupt in endpoints we have */ - __u8 interrupt_in_interval[MAX_NUM_PORTS]; - unsigned char * interrupt_in_buffer[MAX_NUM_PORTS]; - struct urb control_urb[MAX_NUM_PORTS]; - - char num_bulk_in; /* number of bulk in endpoints we have */ - unsigned char * bulk_in_buffer[MAX_NUM_PORTS]; - struct urb read_urb[MAX_NUM_PORTS]; - - char num_bulk_out; /* number of bulk out endpoints we have */ - unsigned char * bulk_out_buffer[MAX_NUM_PORTS]; - int bulk_out_size[MAX_NUM_PORTS]; - struct urb write_urb[MAX_NUM_PORTS]; -}; - - -#define MUST_HAVE_NOT 0x01 -#define MUST_HAVE 0x02 -#define DONT_CARE 0x03 - -#define HAS 0x02 -#define HAS_NOT 0x01 - -#define NUM_DONT_CARE (-1) - -/* local function prototypes */ -static int serial_open (struct tty_struct *tty, struct file * filp); -static void serial_close (struct tty_struct *tty, struct file * filp); -static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count); -static int serial_write_room (struct tty_struct *tty); -static int serial_chars_in_buffer (struct tty_struct *tty); -static void serial_throttle (struct tty_struct * tty); -static void serial_unthrottle (struct tty_struct * tty); - - -/* This structure defines the individual serial converter. */ -struct usb_serial_device_type { - char *name; - __u16 *idVendor; - __u16 *idProduct; - char needs_interrupt_in; - char needs_bulk_in; - char needs_bulk_out; - char num_interrupt_in; - char num_bulk_in; - char num_bulk_out; - char num_ports; /* number of serial ports this device has */ - - /* function call to make before accepting driver */ - int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ - - /* serial function calls */ - int (*open)(struct tty_struct * tty, struct file * filp); - void (*close)(struct tty_struct * tty, struct file * filp); - int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count); - int (*write_room)(struct tty_struct *tty); - int (*chars_in_buffer)(struct tty_struct *tty); - void (*throttle)(struct tty_struct * tty); - void (*unthrottle)(struct tty_struct * tty); -}; - - -/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ -/* need to always compile these in, as some of the other devices use these functions as their own. */ -static int generic_serial_open (struct tty_struct *tty, struct file *filp); -static void generic_serial_close (struct tty_struct *tty, struct file *filp); -static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static int generic_write_room (struct tty_struct *tty); -static int generic_chars_in_buffer (struct tty_struct *tty); - -#ifdef CONFIG_USB_SERIAL_GENERIC -/* All of the device info needed for the Generic Serial Converter */ -static struct usb_serial_device_type generic_device = { - name: "Generic", - idVendor: &vendor, /* use the user specified vendor id */ - idProduct: &product, /* use the user specified product id */ - needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ - needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ - needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 1, - open: generic_serial_open, - close: generic_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, -}; -#endif - -#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) -/* function prototypes for the eTek type converters (this includes Belkin and Peracom) */ -static int etek_serial_open (struct tty_struct *tty, struct file *filp); -static void etek_serial_close (struct tty_struct *tty, struct file *filp); -#endif - -#ifdef CONFIG_USB_SERIAL_BELKIN -/* All of the device info needed for the Belkin Serial Converter */ -static __u16 belkin_vendor_id = BELKIN_VENDOR_ID; -static __u16 belkin_product_id = BELKIN_SERIAL_CONVERTER_ID; -static struct usb_serial_device_type belkin_device = { - name: "Belkin", - idVendor: &belkin_vendor_id, /* the Belkin vendor id */ - idProduct: &belkin_product_id, /* the Belkin serial converter product id */ - needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ - needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ - needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ - num_interrupt_in: 1, - num_bulk_in: 1, - num_bulk_out: 1, - num_ports: 1, - open: etek_serial_open, - close: etek_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, -}; -#endif - - -#ifdef CONFIG_USB_SERIAL_PERACOM -/* All of the device info needed for the Peracom Serial Converter */ -static __u16 peracom_vendor_id = PERACOM_VENDOR_ID; -static __u16 peracom_product_id = PERACOM_SERIAL_CONVERTER_ID; -static struct usb_serial_device_type peracom_device = { - name: "Peracom", - idVendor: &peracom_vendor_id, /* the Peracom vendor id */ - idProduct: &peracom_product_id, /* the Peracom serial converter product id */ - needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ - needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ - needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ - num_ports: 1, - num_interrupt_in: 1, - num_bulk_in: 1, - num_bulk_out: 1, - open: etek_serial_open, - close: etek_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, -}; -#endif - - -#ifdef CONFIG_USB_SERIAL_WHITEHEAT -/* function prototypes for the Connect Tech WhiteHEAT serial converter */ -static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp); -static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp); -static void whiteheat_throttle (struct tty_struct *tty); -static void whiteheat_unthrottle (struct tty_struct *tty); -static int whiteheat_startup (struct usb_serial *serial); - -/* All of the device info needed for the Connect Tech WhiteHEAT */ -static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID; -static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID; -static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID; -static struct usb_serial_device_type whiteheat_fake_device = { - name: "Connect Tech - WhiteHEAT - (prerenumeration)", - idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ - idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */ - needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ - needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ - needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - startup: whiteheat_startup -}; -static struct usb_serial_device_type whiteheat_device = { - name: "Connect Tech - WhiteHEAT", - idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ - idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */ - needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ - needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ - needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ - num_interrupt_in: NUM_DONT_CARE, - num_bulk_in: NUM_DONT_CARE, - num_bulk_out: NUM_DONT_CARE, - num_ports: 4, - open: whiteheat_serial_open, - close: whiteheat_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, - throttle: whiteheat_throttle, - unthrottle: whiteheat_unthrottle -}; -#endif - - -#ifdef CONFIG_USB_SERIAL_VISOR - -/**************************************************************************** - * Handspring Visor Vendor specific request codes (bRequest values) - * A big thank you to Handspring for providing the following information. - * If anyone wants the original file where these values and structures came - * from, send email to . - ****************************************************************************/ - -/**************************************************************************** - * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that - * are available to be transfered to the host for the specified endpoint. - * Currently this is not used, and always returns 0x0001 - ****************************************************************************/ -#define VISOR_REQUEST_BYTES_AVAILABLE 0x01 - -/**************************************************************************** - * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host - * is now closing the pipe. An empty packet is sent in response. - ****************************************************************************/ -#define VISOR_CLOSE_NOTIFICATION 0x02 - -/**************************************************************************** - * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to - * get the endpoints used by the connection. - ****************************************************************************/ -#define VISOR_GET_CONNECTION_INFORMATION 0x03 - - -/**************************************************************************** - * VISOR_GET_CONNECTION_INFORMATION returns data in the following format - ****************************************************************************/ -struct visor_connection_info { - __u16 num_ports; - struct { - __u8 port_function_id; - __u8 port; - } connections[2]; -}; - - -/* struct visor_connection_info.connection[x].port defines: */ -#define VISOR_ENDPOINT_1 0x01 -#define VISOR_ENDPOINT_2 0x02 - -/* struct visor_connection_info.connection[x].port_function_id defines: */ -#define VISOR_FUNCTION_GENERIC 0x00 -#define VISOR_FUNCTION_DEBUGGER 0x01 -#define VISOR_FUNCTION_HOTSYNC 0x02 -#define VISOR_FUNCTION_CONSOLE 0x03 -#define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04 - - -/* function prototypes for a handspring visor */ -static int visor_serial_open (struct tty_struct *tty, struct file *filp); -static void visor_serial_close (struct tty_struct *tty, struct file *filp); -static void visor_throttle (struct tty_struct *tty); -static void visor_unthrottle (struct tty_struct *tty); -static int visor_startup (struct usb_serial *serial); - -/* All of the device info needed for the Handspring Visor */ -static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; -static __u16 handspring_product_id = HANDSPRING_VISOR_ID; -static struct usb_serial_device_type handspring_device = { - name: "Handspring Visor", - idVendor: &handspring_vendor_id, /* the Handspring vendor ID */ - idProduct: &handspring_product_id, /* the Handspring Visor product id */ - needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ - needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ - needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ - num_interrupt_in: 0, - num_bulk_in: 2, - num_bulk_out: 2, - num_ports: 2, - open: visor_serial_open, - close: visor_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer, - throttle: visor_throttle, - unthrottle: visor_unthrottle, - startup: visor_startup -}; -#endif - - -#ifdef CONFIG_USB_SERIAL_FTDI -/* function prototypes for a FTDI serial converter */ -static int ftdi_serial_open (struct tty_struct *tty, struct file *filp); -static void ftdi_serial_close (struct tty_struct *tty, struct file *filp); - -/* All of the device info needed for the Handspring Visor */ -static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; -static __u16 ftdi_product_id = FTDI_SERIAL_CONVERTER_ID; -static struct usb_serial_device_type ftdi_device = { - name: "FTDI", - idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */ - idProduct: &ftdi_product_id, /* the FTDI product id */ - needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ - needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ - needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ - num_interrupt_in: 0, - num_bulk_in: 1, - num_bulk_out: 1, - num_ports: 1, - open: ftdi_serial_open, - close: ftdi_serial_close, - write: generic_serial_write, - write_room: generic_write_room, - chars_in_buffer: generic_chars_in_buffer -}; -#endif - -/* To add support for another serial converter, create a usb_serial_device_type - structure for that device, and add it to this list, making sure that the last - entry is NULL. */ -static struct usb_serial_device_type *usb_serial_devices[] = { -#ifdef CONFIG_USB_SERIAL_GENERIC - &generic_device, -#endif -#ifdef CONFIG_USB_SERIAL_WHITEHEAT - &whiteheat_fake_device, - &whiteheat_device, -#endif -#ifdef CONFIG_USB_SERIAL_BELKIN - &belkin_device, -#endif -#ifdef CONFIG_USB_SERIAL_PERACOM - &peracom_device, -#endif -#ifdef CONFIG_USB_SERIAL_VISOR - &handspring_device, -#endif -#ifdef CONFIG_USB_SERIAL_FTDI - &ftdi_device, -#endif - NULL -}; - - static struct usb_driver usb_serial_driver = { "serial", usb_serial_probe, @@ -532,8 +170,6 @@ -#define SERIAL_PTR_EMPTY ((void *)(-1)) - static struct usb_serial *get_serial_by_minor (int minor) { int i; @@ -592,6 +228,42 @@ } +#ifdef USES_EZUSB_FUNCTIONS +/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ +#define CPUCS_REG 0x7F92 + +static int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest) +{ + int result; + unsigned char *transfer_buffer = kmalloc (length, GFP_KERNEL); + +// dbg("ezusb_writememory %x, %d", address, length); + + if (!transfer_buffer) { + err("ezusb_writememory: kmalloc(%d) failed.", length); + return -ENOMEM; + } + memcpy (transfer_buffer, data, length); + result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300); + kfree (transfer_buffer); + return result; +} + + +static int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) +{ + int response; + dbg("ezusb_set_reset: %d", reset_bit); + response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); + if (response < 0) { + err("ezusb_set_reset %d failed", reset_bit); + } + return (response); +} + +#endif /* USES_EZUSB_FUNCTIONS */ + + static void serial_read_bulk (struct urb *urb) { struct usb_serial *serial = (struct usb_serial *)urb->context; @@ -606,9 +278,16 @@ return; } - if (urb->actual_length) - dbg("%d %s", urb->actual_length, data); - +#ifdef DEBUG + if (urb->actual_length) { + printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); + for (i = 0; i < urb->actual_length; ++i) { + printk ("0x%.2x ", data[i]); + } + printk ("\n"); + } +#endif + if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); @@ -988,38 +667,6 @@ } -static int whiteheat_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest) -{ - int result; - unsigned char *transfer_buffer = kmalloc (length, GFP_KERNEL); - -// dbg("whiteheat_writememory %x, %d", address, length); - - if (!transfer_buffer) { - err("whiteheat_writememory: kmalloc(%d) failed.", length); - return -ENOMEM; - } - memcpy (transfer_buffer, data, length); - result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300); - kfree (transfer_buffer); - return result; -} - -/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ -#define CPUCS_REG 0x7F92 - -static int whiteheat_set_reset (struct usb_serial *serial, unsigned char reset_bit) -{ - int response; - dbg("whiteheat_set_reset: %d", reset_bit); - response = whiteheat_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) { - err("whiteheat_set_reset %d failed", reset_bit); - } - return (response); -} - - /* steps to download the firmware to the WhiteHEAT device: - hold the reset (by writing to the reset bit of the CPUCS register) - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD @@ -1040,52 +687,52 @@ dbg("whiteheat_startup"); - response = whiteheat_set_reset (serial, 1); + response = ezusb_set_reset (serial, 1); record = &whiteheat_loader[0]; while (record->address != 0xffff) { - response = whiteheat_writememory (serial, record->address, + response = ezusb_writememory (serial, record->address, (unsigned char *)record->data, record->data_size, 0xa0); if (response < 0) { - err("whiteheat_writememory failed for loader (%d %04X %p %d)", + err("ezusb_writememory failed for loader (%d %04X %p %d)", response, record->address, record->data, record->data_size); break; } ++record; } - response = whiteheat_set_reset (serial, 0); + response = ezusb_set_reset (serial, 0); record = &whiteheat_firmware[0]; while (record->address < 0x1b40) { ++record; } while (record->address != 0xffff) { - response = whiteheat_writememory (serial, record->address, + response = ezusb_writememory (serial, record->address, (unsigned char *)record->data, record->data_size, 0xa0); if (response < 0) { - err("whiteheat_writememory failed for first firmware step (%d %04X %p %d)", + err("ezusb_writememory failed for first firmware step (%d %04X %p %d)", response, record->address, record->data, record->data_size); break; } ++record; } - response = whiteheat_set_reset (serial, 1); + response = ezusb_set_reset (serial, 1); record = &whiteheat_firmware[0]; while (record->address < 0x1b40) { - response = whiteheat_writememory (serial, record->address, + response = ezusb_writememory (serial, record->address, (unsigned char *)record->data, record->data_size, 0xa0); if (response < 0) { - err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)", + err("ezusb_writememory failed for second firmware step (%d %04X %p %d)", response, record->address, record->data, record->data_size); break; } ++record; } - response = whiteheat_set_reset (serial, 0); + response = ezusb_set_reset (serial, 0); /* we want this device to fail to have a driver assigned to it. */ return (1); @@ -1190,10 +837,9 @@ if (response < 0) { err("visor_startup: error getting connection information"); } else { -#ifdef DEBUG struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer; char *string; - dbg("%s: Number of ports: %d", serial->type->name, connection_info->num_ports); + info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports); for (i = 0; i < connection_info->num_ports; ++i) { switch (connection_info->connections[i].port_function_id) { case VISOR_FUNCTION_GENERIC: @@ -1212,9 +858,8 @@ string = "unknown"; break; } - dbg("%s: port %d, is for %s", serial->type->name, connection_info->connections[i].port, string); + info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i); } -#endif } /* ask for the number of bytes available, but ignore the response as it is broken */ @@ -1280,6 +925,64 @@ #endif + + +#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA +/***************************************************************************** + * Keyspan PDA specific driver functions + *****************************************************************************/ +static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("keyspan_pda_serial_open port %d", port); + + if (serial->active[port]) { + dbg ("device already open"); + return -EINVAL; + } + serial->active[port] = 1; + + /*Start reading from the device*/ + if (usb_submit_urb(&serial->read_urb[port])) + dbg("usb_submit_urb(read bulk) failed"); + + /* Need to do device specific setup here (control lines, baud rate, etc.) */ + /* FIXME */ + + return (0); +} + + +static void keyspan_pda_serial_close(struct tty_struct *tty, struct file * filp) +{ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("keyspan_pda_serial_close port %d", port); + + /* Need to change the control lines here */ + /* FIXME */ + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (&serial->write_urb[port]); + usb_unlink_urb (&serial->read_urb[port]); + serial->active[port] = 0; +} + + +static int keyspan_pda_startup (struct usb_serial *serial) +{ + dbg("keyspan_pda_startup"); + + /* download the firmware here ... */ + /* FIXME */ + + /* we want this device to fail to have a driver assigned to it. */ + return (1); +} +#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */ /***************************************************************************** diff -u --recursive --new-file v2.3.42/linux/drivers/usb/usb-serial.h linux/drivers/usb/usb-serial.h --- v2.3.42/linux/drivers/usb/usb-serial.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/usb-serial.h Tue Feb 8 12:01:59 2000 @@ -0,0 +1,459 @@ +/* + * USB Serial Converter driver + * + * (C) Copyright (C) 1999, 2000 + * 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. + * + * See Documentation/usb/usb-serial.txt for more information on using this driver + * + */ + + +#ifndef __LINUX_USB_SERIAL_H +#define __LINUX_USB_SERIAL_H + +#include + +/* Module information */ +MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"); +MODULE_DESCRIPTION("USB Serial Driver"); + +#ifdef CONFIG_USB_SERIAL_GENERIC +static __u16 vendor = 0x05f9; +static __u16 product = 0xffff; +MODULE_PARM(vendor, "i"); +MODULE_PARM_DESC(vendor, "User specified USB idVendor"); + +MODULE_PARM(product, "i"); +MODULE_PARM_DESC(product, "User specified USB idProduct"); +#endif + + +/* USB Serial devices vendor ids and device ids that this driver supports */ +#define BELKIN_VENDOR_ID 0x056c +#define BELKIN_SERIAL_CONVERTER_ID 0x8007 +#define PERACOM_VENDOR_ID 0x0565 +#define PERACOM_SERIAL_CONVERTER_ID 0x0001 +#define CONNECT_TECH_VENDOR_ID 0x0710 +#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 +#define CONNECT_TECH_WHITE_HEAT_ID 0x8001 +#define HANDSPRING_VENDOR_ID 0x082d +#define HANDSPRING_VISOR_ID 0x0100 +#define FTDI_VENDOR_ID 0x0403 +#define FTDI_SERIAL_CONVERTER_ID 0x8372 +#define KEYSPAN_VENDOR_ID 0x06cd +#define KEYSPAN_PDA_FAKE_ID 0x0103 +#define KEYSPAN_PDA_ID 0x0103 + +#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ +#define SERIAL_TTY_MINORS 16 /* Actually we are allowed 255, but this is good for now */ + + +#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ + +struct usb_serial { + struct usb_device * dev; + struct usb_serial_device_type * type; + void * irq_handle; + unsigned int irqpipe; + struct tty_struct * tty; /* the coresponding tty for this device */ + unsigned char minor; + unsigned char num_ports; /* the number of ports this device has */ + char active[MAX_NUM_PORTS]; /* someone has this device open */ + + char num_interrupt_in; /* number of interrupt in endpoints we have */ + __u8 interrupt_in_interval[MAX_NUM_PORTS]; + unsigned char * interrupt_in_buffer[MAX_NUM_PORTS]; + struct urb control_urb[MAX_NUM_PORTS]; + + char num_bulk_in; /* number of bulk in endpoints we have */ + unsigned char * bulk_in_buffer[MAX_NUM_PORTS]; + struct urb read_urb[MAX_NUM_PORTS]; + + char num_bulk_out; /* number of bulk out endpoints we have */ + unsigned char * bulk_out_buffer[MAX_NUM_PORTS]; + int bulk_out_size[MAX_NUM_PORTS]; + struct urb write_urb[MAX_NUM_PORTS]; +}; + + +#define MUST_HAVE_NOT 0x01 +#define MUST_HAVE 0x02 +#define DONT_CARE 0x03 + +#define HAS 0x02 +#define HAS_NOT 0x01 + +#define NUM_DONT_CARE (-1) + +/* local function prototypes */ +static int serial_open (struct tty_struct *tty, struct file * filp); +static void serial_close (struct tty_struct *tty, struct file * filp); +static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count); +static int serial_write_room (struct tty_struct *tty); +static int serial_chars_in_buffer (struct tty_struct *tty); +static void serial_throttle (struct tty_struct * tty); +static void serial_unthrottle (struct tty_struct * tty); + + +/* This structure defines the individual serial converter. */ +struct usb_serial_device_type { + char *name; + __u16 *idVendor; + __u16 *idProduct; + char needs_interrupt_in; + char needs_bulk_in; + char needs_bulk_out; + char num_interrupt_in; + char num_bulk_in; + char num_bulk_out; + char num_ports; /* number of serial ports this device has */ + + /* function call to make before accepting driver */ + int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ + + /* serial function calls */ + int (*open)(struct tty_struct * tty, struct file * filp); + void (*close)(struct tty_struct * tty, struct file * filp); + int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count); + int (*write_room)(struct tty_struct *tty); + int (*chars_in_buffer)(struct tty_struct *tty); + void (*throttle)(struct tty_struct * tty); + void (*unthrottle)(struct tty_struct * tty); +}; + + +/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ +/* need to always compile these in, as some of the other devices use these functions as their own. */ +static int generic_serial_open (struct tty_struct *tty, struct file *filp); +static void generic_serial_close (struct tty_struct *tty, struct file *filp); +static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); +static int generic_write_room (struct tty_struct *tty); +static int generic_chars_in_buffer (struct tty_struct *tty); + +#ifdef CONFIG_USB_SERIAL_GENERIC +/* All of the device info needed for the Generic Serial Converter */ +static struct usb_serial_device_type generic_device = { + name: "Generic", + idVendor: &vendor, /* use the user specified vendor id */ + idProduct: &product, /* use the user specified product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 1, + open: generic_serial_open, + close: generic_serial_close, + write: generic_serial_write, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, +}; +#endif + +#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) +/* function prototypes for the eTek type converters (this includes Belkin and Peracom) */ +static int etek_serial_open (struct tty_struct *tty, struct file *filp); +static void etek_serial_close (struct tty_struct *tty, struct file *filp); +#endif + +#ifdef CONFIG_USB_SERIAL_BELKIN +/* All of the device info needed for the Belkin Serial Converter */ +static __u16 belkin_vendor_id = BELKIN_VENDOR_ID; +static __u16 belkin_product_id = BELKIN_SERIAL_CONVERTER_ID; +static struct usb_serial_device_type belkin_device = { + name: "Belkin", + idVendor: &belkin_vendor_id, /* the Belkin vendor id */ + idProduct: &belkin_product_id, /* the Belkin serial converter product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: etek_serial_open, + close: etek_serial_close, + write: generic_serial_write, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, +}; +#endif + + +#ifdef CONFIG_USB_SERIAL_PERACOM +/* All of the device info needed for the Peracom Serial Converter */ +static __u16 peracom_vendor_id = PERACOM_VENDOR_ID; +static __u16 peracom_product_id = PERACOM_SERIAL_CONVERTER_ID; +static struct usb_serial_device_type peracom_device = { + name: "Peracom", + idVendor: &peracom_vendor_id, /* the Peracom vendor id */ + idProduct: &peracom_product_id, /* the Peracom serial converter product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_ports: 1, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + open: etek_serial_open, + close: etek_serial_close, + write: generic_serial_write, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, +}; +#endif + + +#ifdef CONFIG_USB_SERIAL_WHITEHEAT +/* function prototypes for the Connect Tech WhiteHEAT serial converter */ +static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp); +static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp); +static void whiteheat_throttle (struct tty_struct *tty); +static void whiteheat_unthrottle (struct tty_struct *tty); +static int whiteheat_startup (struct usb_serial *serial); + +/* All of the device info needed for the Connect Tech WhiteHEAT */ +static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID; +static __u16 connecttech_whiteheat_fake_product_id = CONNECT_TECH_FAKE_WHITE_HEAT_ID; +static __u16 connecttech_whiteheat_product_id = CONNECT_TECH_WHITE_HEAT_ID; +static struct usb_serial_device_type whiteheat_fake_device = { + name: "Connect Tech - WhiteHEAT - (prerenumeration)", + idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ + idProduct: &connecttech_whiteheat_fake_product_id, /* the White Heat initial product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + startup: whiteheat_startup +}; +static struct usb_serial_device_type whiteheat_device = { + name: "Connect Tech - WhiteHEAT", + idVendor: &connecttech_vendor_id, /* the Connect Tech vendor id */ + idProduct: &connecttech_whiteheat_product_id, /* the White Heat real product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + num_ports: 4, + open: whiteheat_serial_open, + close: whiteheat_serial_close, + write: generic_serial_write, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, + throttle: whiteheat_throttle, + unthrottle: whiteheat_unthrottle +}; +#endif + + +#ifdef CONFIG_USB_SERIAL_VISOR + +/**************************************************************************** + * Handspring Visor Vendor specific request codes (bRequest values) + * A big thank you to Handspring for providing the following information. + * If anyone wants the original file where these values and structures came + * from, send email to . + ****************************************************************************/ + +/**************************************************************************** + * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that + * are available to be transfered to the host for the specified endpoint. + * Currently this is not used, and always returns 0x0001 + ****************************************************************************/ +#define VISOR_REQUEST_BYTES_AVAILABLE 0x01 + +/**************************************************************************** + * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host + * is now closing the pipe. An empty packet is sent in response. + ****************************************************************************/ +#define VISOR_CLOSE_NOTIFICATION 0x02 + +/**************************************************************************** + * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to + * get the endpoints used by the connection. + ****************************************************************************/ +#define VISOR_GET_CONNECTION_INFORMATION 0x03 + + +/**************************************************************************** + * VISOR_GET_CONNECTION_INFORMATION returns data in the following format + ****************************************************************************/ +struct visor_connection_info { + __u16 num_ports; + struct { + __u8 port_function_id; + __u8 port; + } connections[2]; +}; + + +/* struct visor_connection_info.connection[x].port defines: */ +#define VISOR_ENDPOINT_1 0x01 +#define VISOR_ENDPOINT_2 0x02 + +/* struct visor_connection_info.connection[x].port_function_id defines: */ +#define VISOR_FUNCTION_GENERIC 0x00 +#define VISOR_FUNCTION_DEBUGGER 0x01 +#define VISOR_FUNCTION_HOTSYNC 0x02 +#define VISOR_FUNCTION_CONSOLE 0x03 +#define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04 + + +/* function prototypes for a handspring visor */ +static int visor_serial_open (struct tty_struct *tty, struct file *filp); +static void visor_serial_close (struct tty_struct *tty, struct file *filp); +static void visor_throttle (struct tty_struct *tty); +static void visor_unthrottle (struct tty_struct *tty); +static int visor_startup (struct usb_serial *serial); + +/* All of the device info needed for the Handspring Visor */ +static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; +static __u16 handspring_product_id = HANDSPRING_VISOR_ID; +static struct usb_serial_device_type handspring_device = { + name: "Handspring Visor", + idVendor: &handspring_vendor_id, /* the Handspring vendor ID */ + idProduct: &handspring_product_id, /* the Handspring Visor product id */ + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 2, + num_bulk_out: 2, + num_ports: 2, + open: visor_serial_open, + close: visor_serial_close, + write: generic_serial_write, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer, + throttle: visor_throttle, + unthrottle: visor_unthrottle, + startup: visor_startup +}; +#endif + + +#ifdef CONFIG_USB_SERIAL_FTDI +/* function prototypes for a FTDI serial converter */ +static int ftdi_serial_open (struct tty_struct *tty, struct file *filp); +static void ftdi_serial_close (struct tty_struct *tty, struct file *filp); + +/* All of the device info needed for the Handspring Visor */ +static __u16 ftdi_vendor_id = FTDI_VENDOR_ID; +static __u16 ftdi_product_id = FTDI_SERIAL_CONVERTER_ID; +static struct usb_serial_device_type ftdi_device = { + name: "FTDI", + idVendor: &ftdi_vendor_id, /* the FTDI vendor ID */ + idProduct: &ftdi_product_id, /* the FTDI product id */ + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: ftdi_serial_open, + close: ftdi_serial_close, + write: generic_serial_write, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer +}; +#endif + + +#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA +/* function prototypes for a FTDI serial converter */ +static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp); +static void keyspan_pda_serial_close (struct tty_struct *tty, struct file *filp); +static int keyspan_pda_startup (struct usb_serial *serial); + +/* All of the device info needed for the Handspring Visor */ +static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID; +static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID; +static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID; +static struct usb_serial_device_type keyspan_pda_fake_device = { + name: "Keyspan PDA - (prerenumeration)", + idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */ + idProduct: &keyspan_pda_fake_product_id, /* the Keyspan PDA initial product id */ + needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */ + needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */ + needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */ + num_interrupt_in: NUM_DONT_CARE, + num_bulk_in: NUM_DONT_CARE, + num_bulk_out: NUM_DONT_CARE, + startup: keyspan_pda_startup +}; +static struct usb_serial_device_type keyspan_pda_device = { + name: "Keyspan PDA", + idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */ + idProduct: &keyspan_pda_product_id, /* the Keyspan PDA product id */ + needs_interrupt_in: MUST_HAVE_NOT, /* this device must not have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 0, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: keyspan_pda_serial_open, + close: keyspan_pda_serial_close, + write: generic_serial_write, + write_room: generic_write_room, + chars_in_buffer: generic_chars_in_buffer +}; +#endif + +/* To add support for another serial converter, create a usb_serial_device_type + structure for that device, and add it to this list, making sure that the last + entry is NULL. */ +static struct usb_serial_device_type *usb_serial_devices[] = { +#ifdef CONFIG_USB_SERIAL_GENERIC + &generic_device, +#endif +#ifdef CONFIG_USB_SERIAL_WHITEHEAT + &whiteheat_fake_device, + &whiteheat_device, +#endif +#ifdef CONFIG_USB_SERIAL_BELKIN + &belkin_device, +#endif +#ifdef CONFIG_USB_SERIAL_PERACOM + &peracom_device, +#endif +#ifdef CONFIG_USB_SERIAL_VISOR + &handspring_device, +#endif +#ifdef CONFIG_USB_SERIAL_FTDI + &ftdi_device, +#endif +#ifdef CONFIG_USB_SERIAL_KEYSPAN_PDA + &keyspan_pda_fake_device, + &keyspan_pda_device, +#endif + NULL +}; + + +/* determine if we should include the EzUSB loader functions */ +#if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_WHITEHEAT) + #define USES_EZUSB_FUNCTIONS +#else + #undef USES_EZUSB_FUNCTIONS +#endif + + +/* used to mark that a pointer is empty (and not NULL) */ +#define SERIAL_PTR_EMPTY ((void *)(-1)) + + +#endif /* ifdef __LINUX_USB_SERIAL_H */ + diff -u --recursive --new-file v2.3.42/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c --- v2.3.42/linux/drivers/usb/usb-uhci.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/usb-uhci.c Tue Feb 8 18:49:45 2000 @@ -12,10 +12,9 @@ * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap * - * $Id: usb-uhci.c,v 1.169 2000/01/20 19:50:11 acher Exp $ + * $Id: usb-uhci.c,v 1.185 2000/02/05 21:29:19 acher Exp $ */ -#include #include #include #include @@ -34,73 +33,93 @@ #include #include +/* This enables more detailed sanity checks in submit_iso */ +//#define ISO_SANITY_CHECK + /* This enables debug printks */ -//#define DEBUG +#define DEBUG + /* This enables all symbols to be exported, to ease debugging oopses */ -#define DEBUG_SYMBOLS +//#define DEBUG_SYMBOLS + /* This enables an extra UHCI slab for memory debugging */ -//#define DEBUG_SLAB +#define DEBUG_SLAB #include "usb.h" #include "usb-uhci.h" #include "usb-uhci-debug.h" -#ifdef CONFIG_APM -#include -static int handle_apm_event (apm_event_t event); -#endif +#undef DEBUG +#undef dbg +#define dbg(format, arg...) do {} while (0) + +#include +static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data); #ifdef DEBUG_SYMBOLS -#define _static -#ifndef EXPORT_SYMTAB -#define EXPORT_SYMTAB -#endif + #define _static + #ifndef EXPORT_SYMTAB + #define EXPORT_SYMTAB + #endif #else -#define _static static + #define _static static #endif #ifdef DEBUG_SLAB -static kmem_cache_t *uhci_desc_kmem; -static kmem_cache_t *urb_priv_kmem; + static kmem_cache_t *uhci_desc_kmem; + static kmem_cache_t *urb_priv_kmem; #endif -_static int rh_submit_urb (purb_t purb); -_static int rh_unlink_urb (purb_t purb); -static puhci_t devs = NULL; +#define USE_CTRL_DEPTH_FIRST 1 // 0: Breadth first, 1: Depth first (standard) + +//#define USE_RECLAMATION_LOOP + +_static int rh_submit_urb (urb_t *urb); +_static int rh_unlink_urb (urb_t *urb); +_static int delete_qh (uhci_t *s, uhci_desc_t *qh); + +static uhci_t *devs = NULL; /* used by userspace UHCI data structure dumper */ -puhci_t *uhci_devices = &devs; +uhci_t **uhci_devices = &devs; + +/*-------------------------------------------------------------------*/ +// Cleans up collected QHs +void clean_descs(uhci_t *s, int force) +{ + struct list_head *q; + uhci_desc_t *qh; + int now=UHCI_GET_CURRENT_FRAME(s); + + q=s->free_desc.prev; + while (q != &s->free_desc) { + qh = list_entry (q, uhci_desc_t, horizontal); + if ((qh->last_used!=now) || force) + delete_qh(s,qh); + q=qh->horizontal.prev; + } +} /*-------------------------------------------------------------------*/ -_static void queue_urb (puhci_t s, struct list_head *p, int do_lock) +_static void queue_urb (uhci_t *s, struct list_head *p) { unsigned long flags=0; - if (do_lock) - spin_lock_irqsave (&s->urb_list_lock, flags); - + spin_lock_irqsave (&s->urb_list_lock, flags); + list_add_tail (p, &s->urb_list); - if (do_lock) - spin_unlock_irqrestore (&s->urb_list_lock, flags); + spin_unlock_irqrestore (&s->urb_list_lock, flags); } /*-------------------------------------------------------------------*/ -_static void dequeue_urb (puhci_t s, struct list_head *p, int do_lock) +_static void dequeue_urb (uhci_t *s, struct list_head *p) { - unsigned long flags=0; - - if (do_lock) - spin_lock_irqsave (&s->urb_list_lock, flags); - list_del (p); - if (do_lock) - spin_unlock_irqrestore (&s->urb_list_lock, flags); } - /*-------------------------------------------------------------------*/ -_static int alloc_td (puhci_desc_t * new, int flags) +_static int alloc_td (uhci_desc_t ** new, int flags) { #ifdef DEBUG_SLAB *new= kmem_cache_alloc(uhci_desc_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL); @@ -109,10 +128,8 @@ #endif if (!*new) return -ENOMEM; - - memset (*new, 0, sizeof (uhci_desc_t)); + memset (*new, 0, sizeof (uhci_desc_t)); (*new)->hw.td.link = UHCI_PTR_TERM | (flags & UHCI_PTR_BITS); // last by default - (*new)->type = TD_TYPE; mb(); INIT_LIST_HEAD (&(*new)->vertical); @@ -122,7 +139,7 @@ } /*-------------------------------------------------------------------*/ /* insert td at last position in td-list of qh (vertical) */ -_static int insert_td (puhci_t s, puhci_desc_t qh, puhci_desc_t new, int flags) +_static int insert_td (uhci_t *s, uhci_desc_t *qh, uhci_desc_t* new, int flags) { uhci_desc_t *prev; unsigned long xxx; @@ -131,14 +148,14 @@ list_add_tail (&new->vertical, &qh->vertical); - if (qh->hw.qh.element & UHCI_PTR_TERM) { + prev = list_entry (new->vertical.prev, uhci_desc_t, vertical); + + if (qh == prev ) { // virgin qh without any tds - qh->hw.qh.element = virt_to_bus (new); /* QH's cannot have the DEPTH bit set */ + qh->hw.qh.element = virt_to_bus (new); } else { - // already tds inserted - prev = list_entry (new->vertical.prev, uhci_desc_t, vertical); - // implicitely remove TERM bit of prev + // already tds inserted, implicitely remove TERM bit of prev prev->hw.td.link = virt_to_bus (new) | (flags & UHCI_PTR_DEPTH); } mb(); @@ -148,61 +165,62 @@ } /*-------------------------------------------------------------------*/ /* insert new_td after td (horizontal) */ -_static int insert_td_horizontal (puhci_t s, puhci_desc_t td, puhci_desc_t new, int flags) +_static int insert_td_horizontal (uhci_t *s, uhci_desc_t *td, uhci_desc_t* new) { uhci_desc_t *next; - unsigned long xxx; + unsigned long flags; - spin_lock_irqsave (&s->td_lock, xxx); + spin_lock_irqsave (&s->td_lock, flags); next = list_entry (td->horizontal.next, uhci_desc_t, horizontal); - new->hw.td.link = td->hw.td.link; - mb(); list_add (&new->horizontal, &td->horizontal); + new->hw.td.link = td->hw.td.link; td->hw.td.link = virt_to_bus (new); mb(); - spin_unlock_irqrestore (&s->td_lock, xxx); + spin_unlock_irqrestore (&s->td_lock, flags); return 0; } /*-------------------------------------------------------------------*/ -_static int unlink_td (puhci_t s, puhci_desc_t element) +_static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink) { uhci_desc_t *next, *prev; int dir = 0; - unsigned long xxx; + unsigned long flags; - spin_lock_irqsave (&s->td_lock, xxx); + spin_lock_irqsave (&s->td_lock, flags); next = list_entry (element->vertical.next, uhci_desc_t, vertical); if (next == element) { dir = 1; - next = list_entry (element->horizontal.next, uhci_desc_t, horizontal); prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal); } - else { + else prev = list_entry (element->vertical.prev, uhci_desc_t, vertical); - } - - if (prev->type == TD_TYPE) - prev->hw.td.link = element->hw.td.link; - else - prev->hw.qh.element = element->hw.td.link; + if (phys_unlink) { + // really remove HW linking + if (prev->type == TD_TYPE) + prev->hw.td.link = element->hw.td.link; + else + prev->hw.qh.element = element->hw.td.link; + } + + element->hw.td.link=UHCI_PTR_TERM; mb (); - + if (dir == 0) list_del (&element->vertical); else list_del (&element->horizontal); - spin_unlock_irqrestore (&s->td_lock, xxx); + spin_unlock_irqrestore (&s->td_lock, flags); return 0; } /*-------------------------------------------------------------------*/ -_static int delete_desc (puhci_desc_t element) +_static int delete_desc (uhci_desc_t *element) { #ifdef DEBUG_SLAB kmem_cache_free(uhci_desc_kmem, element); @@ -213,7 +231,7 @@ } /*-------------------------------------------------------------------*/ // Allocates qh element -_static int alloc_qh (puhci_desc_t * new) +_static int alloc_qh (uhci_desc_t ** new) { #ifdef DEBUG_SLAB *new= kmem_cache_alloc(uhci_desc_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL); @@ -222,11 +240,11 @@ #endif if (!*new) return -ENOMEM; - memset (*new, 0, sizeof (uhci_desc_t)); (*new)->hw.qh.head = UHCI_PTR_TERM; (*new)->hw.qh.element = UHCI_PTR_TERM; (*new)->type = QH_TYPE; + mb(); INIT_LIST_HEAD (&(*new)->horizontal); INIT_LIST_HEAD (&(*new)->vertical); @@ -238,19 +256,18 @@ /*-------------------------------------------------------------------*/ // inserts new qh before/after the qh at pos // flags: 0: insert before pos, 1: insert after pos (for low speed transfers) -_static int insert_qh (puhci_t s, puhci_desc_t pos, puhci_desc_t new, int flags) +_static int insert_qh (uhci_t *s, uhci_desc_t *pos, uhci_desc_t *new, int order) { - puhci_desc_t old; - unsigned long xxx; + uhci_desc_t *old; + unsigned long flags; - spin_lock_irqsave (&s->qh_lock, xxx); + spin_lock_irqsave (&s->qh_lock, flags); - if (!flags) { + if (!order) { // (OLD) (POS) -> (OLD) (NEW) (POS) old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal); list_add_tail (&new->horizontal, &pos->horizontal); new->hw.qh.head = MAKE_QH_ADDR (pos) ; - mb(); if (!(old->hw.qh.head & UHCI_PTR_TERM)) old->hw.qh.head = MAKE_QH_ADDR (new) ; } @@ -259,57 +276,57 @@ old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal); list_add (&new->horizontal, &pos->horizontal); new->hw.qh.head = MAKE_QH_ADDR (old); - mb(); pos->hw.qh.head = MAKE_QH_ADDR (new) ; } mb (); - spin_unlock_irqrestore (&s->qh_lock, xxx); + spin_unlock_irqrestore (&s->qh_lock, flags); return 0; } /*-------------------------------------------------------------------*/ -_static int unlink_qh (puhci_t s, puhci_desc_t element) +_static int unlink_qh (uhci_t *s, uhci_desc_t *element) { - puhci_desc_t next, prev; - unsigned long xxx; + uhci_desc_t *prev; + unsigned long flags; - spin_lock_irqsave (&s->qh_lock, xxx); + spin_lock_irqsave (&s->qh_lock, flags); - next = list_entry (element->horizontal.next, uhci_desc_t, horizontal); prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal); prev->hw.qh.head = element->hw.qh.head; + + list_del(&element->horizontal); + mb (); - list_del (&element->horizontal); - - spin_unlock_irqrestore (&s->qh_lock, xxx); + spin_unlock_irqrestore (&s->qh_lock, flags); return 0; } /*-------------------------------------------------------------------*/ -_static int delete_qh (puhci_t s, puhci_desc_t qh) +_static int delete_qh (uhci_t *s, uhci_desc_t *qh) { - puhci_desc_t td; + uhci_desc_t *td; struct list_head *p; - - list_del (&qh->horizontal); + list_del (&qh->horizontal); + while ((p = qh->vertical.next) != &qh->vertical) { td = list_entry (p, uhci_desc_t, vertical); - unlink_td (s, td); + dbg("unlink td @ %p",td); + unlink_td (s, td, 0); // no physical unlink delete_desc (td); } - + delete_desc (qh); return 0; } /*-------------------------------------------------------------------*/ -_static void clean_td_chain (puhci_desc_t td) +_static void clean_td_chain (uhci_desc_t *td) { struct list_head *p; - puhci_desc_t td1; + uhci_desc_t *td1; if (!td) return; @@ -323,13 +340,15 @@ } /*-------------------------------------------------------------------*/ // Removes ALL qhs in chain (paranoia!) -_static void cleanup_skel (puhci_t s) +_static void cleanup_skel (uhci_t *s) { unsigned int n; - puhci_desc_t td; + uhci_desc_t *td; dbg("cleanup_skel"); - + + clean_descs(s,1); + for (n = 0; n < 8; n++) { td = s->int_chain[n]; clean_td_chain (td); @@ -349,13 +368,15 @@ if (s->control_chain) { // completed init_skel? struct list_head *p; - puhci_desc_t qh, qh1; + uhci_desc_t *qh, *qh1; qh = s->control_chain; while ((p = qh->horizontal.next) != &qh->horizontal) { qh1 = list_entry (p, uhci_desc_t, horizontal); + dbg("delete_qh @ %p",qh1); delete_qh (s, qh1); } + dbg("delete_qh last @ %p",qh); delete_qh (s, qh); } else { @@ -371,10 +392,10 @@ /*-------------------------------------------------------------------*/ // allocates framelist and qh-skeletons // only HW-links provide continous linking, SW-links stay in their domain (ISO/INT) -_static int init_skel (puhci_t s) +_static int init_skel (uhci_t *s) { int n, ret; - puhci_desc_t qh, td; + uhci_desc_t *qh, *td; dbg("init_skel"); @@ -386,7 +407,7 @@ memset (s->framelist, 0, 4096); dbg("allocating iso desc pointer list"); - s->iso_td = (puhci_desc_t *) kmalloc (1024 * sizeof (puhci_desc_t), GFP_KERNEL); + s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL); if (!s->iso_td) goto init_skel_cleanup; @@ -429,13 +450,19 @@ insert_qh (s, s->bulk_chain, qh, 0); s->control_chain = qh; + +#ifdef USE_RECLAMATION_LOOP + s->chain_end->hw.qh.head=virt_to_bus(s->control_chain)|UHCI_PTR_QH; + info("Using loop for bandwidth reclamation."); +#endif + for (n = 0; n < 8; n++) s->int_chain[n] = 0; dbg("allocating skeleton INT-TDs"); for (n = 0; n < 8; n++) { - puhci_desc_t td; + uhci_desc_t *td; alloc_td (&td, 0); if (!td) @@ -456,12 +483,12 @@ int m, o; dbg("framelist[%i]=%x",n,s->framelist[n]); if ((n&127)==127) - ((puhci_desc_t) s->iso_td[n])->hw.td.link = virt_to_bus(s->int_chain[0]); + ((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus(s->int_chain[0]); else { for (o = 1, m = 2; m <= 128; o++, m += m) { // n&(m-1) = n%m if ((n & (m - 1)) == ((m - 1) / 2)) { - ((puhci_desc_t) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]); + ((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]); } } } @@ -478,7 +505,7 @@ } /*-------------------------------------------------------------------*/ -_static void fill_td (puhci_desc_t td, int status, int info, __u32 buffer) +_static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer) { td->hw.td.status = status; td->hw.td.info = info; @@ -489,15 +516,16 @@ // LOW LEVEL STUFF // assembles QHs und TDs for control, bulk and iso /*-------------------------------------------------------------------*/ -_static int uhci_submit_control_urb (purb_t purb) +_static int uhci_submit_control_urb (urb_t *urb) { - puhci_desc_t qh, td; - puhci_t s = (puhci_t) purb->dev->bus->hcpriv; - purb_priv_t purb_priv = purb->hcpriv; + uhci_desc_t *qh, *td; + uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv; + urb_priv_t *urb_priv = urb->hcpriv; unsigned long destination, status; - int maxsze = usb_maxpacket (purb->dev, purb->pipe, usb_pipeout (purb->pipe)); + int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)); unsigned long len, bytesrequested; char *data; + int depth_first=USE_CTRL_DEPTH_FIRST; // UHCI descriptor chasing method dbg("uhci_submit_control start"); alloc_qh (&qh); // alloc qh for this request @@ -505,7 +533,7 @@ if (!qh) return -ENOMEM; - alloc_td (&td, UHCI_PTR_DEPTH); // get td for setup stage + alloc_td (&td, UHCI_PTR_DEPTH * depth_first); // get td for setup stage if (!td) { delete_qh (s, qh); @@ -513,40 +541,42 @@ } /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (purb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; + destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; /* 3 errors */ - status = (purb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | - (purb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); + status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | + (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); /* Build the TD for the control request, try forever, 8 bytes of data */ - fill_td (td, status, destination | (7 << 21), virt_to_bus (purb->setup_packet)); - - /* If direction is "send", change the frame from SETUP (0x2D) - to OUT (0xE1). Else change it from SETUP to IN (0x69). */ - - destination ^= (USB_PID_SETUP ^ USB_PID_IN); /* SETUP -> IN */ - - if (usb_pipeout (purb->pipe)) - destination ^= (USB_PID_IN ^ USB_PID_OUT); /* IN -> OUT */ + fill_td (td, status, destination | (7 << 21), virt_to_bus (urb->setup_packet)); insert_td (s, qh, td, 0); // queue 'setup stage'-td in qh #if 0 - dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", purb->pipe, - purb->setup_packet[0], purb->setup_packet[1], purb->setup_packet[2], purb->setup_packet[3], - purb->setup_packet[4], purb->setup_packet[5], purb->setup_packet[6], purb->setup_packet[7]); + dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe, + urb->setup_packet[0], urb->setup_packet[1], urb->setup_packet[2], urb->setup_packet[3], + urb->setup_packet[4], urb->setup_packet[5], urb->setup_packet[6], urb->setup_packet[7]); //uhci_show_td(td); #endif /* Build the DATA TD's */ - len = purb->transfer_buffer_length; + len = urb->transfer_buffer_length; bytesrequested = len; - data = purb->transfer_buffer; + data = urb->transfer_buffer; + + /* If direction is "send", change the frame from SETUP (0x2D) + to OUT (0xE1). Else change it from SETUP to IN (0x69). */ + + destination &= ~UHCI_PID; + if (usb_pipeout (urb->pipe)) + destination |= USB_PID_OUT; + else + destination |= USB_PID_IN; + while (len > 0) { int pktsze = len; - alloc_td (&td, UHCI_PTR_DEPTH); + alloc_td (&td, UHCI_PTR_DEPTH * depth_first); if (!td) { delete_qh (s, qh); return -ENOMEM; @@ -560,7 +590,7 @@ fill_td (td, status, destination | ((pktsze - 1) << 21), virt_to_bus (data)); // Status, pktsze bytes of data - insert_td (s, qh, td, UHCI_PTR_DEPTH); // queue 'data stage'-td in qh + insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first); // queue 'data stage'-td in qh data += pktsze; len -= pktsze; @@ -568,9 +598,10 @@ /* Build the final TD for control status */ /* It's only IN if the pipe is out AND we aren't expecting data */ - destination &= ~0xFF; - - if (usb_pipeout (purb->pipe) | (bytesrequested == 0)) + + destination &= ~UHCI_PID; + + if (usb_pipeout (urb->pipe) || (bytesrequested == 0)) destination |= USB_PID_IN; else destination |= USB_PID_OUT; @@ -583,23 +614,24 @@ delete_qh (s, qh); return -ENOMEM; } + status &=~TD_CTRL_SPD; /* no limit on errors on final packet , 0 bytes of data */ fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21), 0); - insert_td (s, qh, td, UHCI_PTR_DEPTH); // queue status td + insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first); // queue status td + list_add (&qh->desc_list, &urb_priv->desc_list); - list_add (&qh->desc_list, &purb_priv->desc_list); + urb->status = -EINPROGRESS; + queue_urb (s, &urb->urb_list); // queue before inserting in desc chain - purb->status = USB_ST_URB_PENDING; - queue_urb (s, &purb->urb_list,1); // queue before inserting in desc chain + qh->hw.qh.element&=~UHCI_PTR_TERM; //uhci_show_queue(qh); - /* Start it up... put low speed first */ - if (purb->pipe & TD_CTRL_LS) + if (urb->pipe & TD_CTRL_LS) insert_qh (s, s->control_chain, qh, 1); // insert after control chain else insert_qh (s, s->bulk_chain, qh, 0); // insert before bulk chain @@ -609,22 +641,26 @@ return 0; } /*-------------------------------------------------------------------*/ -_static int uhci_submit_bulk_urb (purb_t purb) +_static int uhci_submit_bulk_urb (urb_t *urb) { - puhci_t s = (puhci_t) purb->dev->bus->hcpriv; - purb_priv_t purb_priv = purb->hcpriv; - puhci_desc_t qh, td; + uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv; + urb_priv_t *urb_priv = urb->hcpriv; + uhci_desc_t *qh, *td; unsigned long destination, status; char *data; - unsigned int pipe = purb->pipe; - int maxsze = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)); + unsigned int pipe = urb->pipe; + int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)); int info, len; /* shouldn't the clear_halt be done in the USB core or in the client driver? - Thomas */ - if (usb_endpoint_halted (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) && - usb_clear_halt (purb->dev, usb_pipeendpoint (pipe) | (pipe & USB_DIR_IN))) + if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) && + usb_clear_halt (urb->dev, usb_pipeendpoint (pipe) | (pipe & USB_DIR_IN))) return -EPIPE; - + if (urb->transfer_buffer_length < 0) { + err("Negative transfer length in submit_bulk"); + return -EINVAL; + } + if (!maxsze) return -EMSGSIZE; /* FIXME: should tell the client that the endpoint is invalid, i.e. not in the descriptor */ @@ -639,14 +675,14 @@ /* 3 errors */ status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | - ((purb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27); + ((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27); /* Build the TDs for the bulk request */ - len = purb->transfer_buffer_length; - data = purb->transfer_buffer; + len = urb->transfer_buffer_length; + data = urb->transfer_buffer; dbg("uhci_submit_bulk_urb: pipe %x, len %d", pipe, len); - while (len > 0) { + do { // TBD: Really allow zero-length packets? int pktsze = len; alloc_td (&td, UHCI_PTR_DEPTH); @@ -660,8 +696,8 @@ pktsze = maxsze; // pktsze bytes of data - info = destination | ((pktsze - 1) << 21) | - (usb_gettoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE); + info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) | + (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE); fill_td (td, status, info, virt_to_bus (data)); @@ -675,13 +711,15 @@ insert_td (s, qh, td, UHCI_PTR_DEPTH); /* Alternate Data0/1 (start with Data0) */ - usb_dotoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)); - } + usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)); + } while (len > 0); - list_add (&qh->desc_list, &purb_priv->desc_list); + list_add (&qh->desc_list, &urb_priv->desc_list); - purb->status = USB_ST_URB_PENDING; - queue_urb (s, &purb->urb_list,1); + urb->status = -EINPROGRESS; + queue_urb (s, &urb->urb_list); + + qh->hw.qh.element&=~UHCI_PTR_TERM; insert_qh (s, s->chain_end, qh, 0); // insert before end marker //uhci_show_queue(s->bulk_chain); @@ -693,51 +731,50 @@ // unlinks an urb by dequeuing its qh, waits some frames and forgets it // Problem: unlinking in interrupt requires waiting for one frame (udelay) // to allow the whole structures to be safely removed -_static int uhci_unlink_urb (purb_t purb) +_static int uhci_unlink_urb (urb_t *urb) { - puhci_t s; - puhci_desc_t qh; - puhci_desc_t td; - purb_priv_t purb_priv; + uhci_t *s; + uhci_desc_t *qh; + uhci_desc_t *td; + urb_priv_t *urb_priv; unsigned long flags=0; + struct list_head *p; - if (!purb) // you never know... - return -1; + if (!urb || !urb->dev) // you never know... + return -EINVAL; - s = (puhci_t) purb->dev->bus->hcpriv; // get pointer to uhci struct + s = (uhci_t*) urb->dev->bus->hcpriv; // get pointer to uhci struct - if (usb_pipedevice (purb->pipe) == s->rh.devnum) - return rh_unlink_urb (purb); + if (usb_pipedevice (urb->pipe) == s->rh.devnum) + return rh_unlink_urb (urb); - if(!in_interrupt()) { - spin_lock_irqsave (&s->unlink_urb_lock, flags); // do not allow interrupts - } - - //dbg("unlink_urb called %p",purb); - if (purb->status == USB_ST_URB_PENDING) { + if (!urb->hcpriv) // you never know... + return -EINVAL; + + //dbg("unlink_urb called %p",urb); + + spin_lock_irqsave (&s->urb_list_lock, flags); + + if (urb->status == -EINPROGRESS) { // URB probably still in work - purb_priv = purb->hcpriv; - dequeue_urb (s, &purb->urb_list,1); - purb->status = USB_ST_URB_KILLED; // mark urb as killed + dequeue_urb (s, &urb->urb_list); + s->unlink_urb_done=1; + spin_unlock_irqrestore (&s->urb_list_lock, flags); - if(!in_interrupt()) { - spin_unlock_irqrestore (&s->unlink_urb_lock, flags); // allow interrupts from here - } + urb->status = -ENOENT; // mark urb as killed + urb_priv = urb->hcpriv; - switch (usb_pipetype (purb->pipe)) { + switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: case PIPE_INTERRUPT: - for (p = purb_priv->desc_list.next; p != &purb_priv->desc_list; p = p->next) { + for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) { td = list_entry (p, uhci_desc_t, desc_list); - unlink_td (s, td); + unlink_td (s, td, 1); } // wait at least 1 Frame - if (in_interrupt ()) - udelay (1000); - else - wait_ms(1); - while ((p = purb_priv->desc_list.next) != &purb_priv->desc_list) { + uhci_wait_ms(1); + while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) { td = list_entry (p, uhci_desc_t, desc_list); list_del (p); delete_desc (td); @@ -746,57 +783,51 @@ case PIPE_BULK: case PIPE_CONTROL: - qh = list_entry (purb_priv->desc_list.next, uhci_desc_t, desc_list); + qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list); unlink_qh (s, qh); // remove this qh from qh-list + qh->last_used=UHCI_GET_CURRENT_FRAME(s); + list_add_tail (&qh->horizontal, &s->free_desc); // mark for later deletion // wait at least 1 Frame - - if (in_interrupt ()) - udelay (1000); - else - wait_ms(1); - delete_qh (s, qh); // remove it physically - + uhci_wait_ms(1); } #ifdef DEBUG_SLAB - kmem_cache_free(urb_priv_kmem, purb->hcpriv); + kmem_cache_free(urb_priv_kmem, urb->hcpriv); #else - kfree (purb->hcpriv); + kfree (urb->hcpriv); #endif - if (purb->complete) { + if (urb->complete) { dbg("unlink_urb: calling completion"); - purb->complete ((struct urb *) purb); - usb_dec_dev_use (purb->dev); + urb->complete ((struct urb *) urb); } + usb_dec_dev_use (urb->dev); return 0; } - else { - if(!in_interrupt()) - spin_unlock_irqrestore (&s->unlink_urb_lock, flags); // allow interrupts from here - } - + else + spin_unlock_irqrestore (&s->urb_list_lock, flags); return 0; } /*-------------------------------------------------------------------*/ // In case of ASAP iso transfer, search the URB-list for already queued URBs // for this EP and calculate the earliest start frame for the new // URB (easy seamless URB continuation!) -_static int find_iso_limits (purb_t purb, unsigned int *start, unsigned int *end) +_static int find_iso_limits (urb_t *urb, unsigned int *start, unsigned int *end) { - purb_t u, last_urb = NULL; - puhci_t s = (puhci_t) purb->dev->bus->hcpriv; - struct list_head *p = s->urb_list.next; + urb_t *u, *last_urb = NULL; + uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv; + struct list_head *p; int ret=-1; unsigned long flags; spin_lock_irqsave (&s->urb_list_lock, flags); + p=s->urb_list.next; for (; p != &s->urb_list; p = p->next) { u = list_entry (p, urb_t, urb_list); // look for pending URBs with identical pipe handle // works only because iso doesn't toggle the data bit! - if ((purb->pipe == u->pipe) && (purb->dev == u->dev) && (u->status == USB_ST_URB_PENDING)) { + if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) { if (!last_urb) *start = u->start_frame; last_urb = u; @@ -816,40 +847,40 @@ /*-------------------------------------------------------------------*/ // adjust start_frame according to scheduling constraints (ASAP etc) -_static int iso_find_start (purb_t purb) +_static int iso_find_start (urb_t *urb) { - puhci_t s = (puhci_t) purb->dev->bus->hcpriv; + uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv; unsigned int now; unsigned int start_limit = 0, stop_limit = 0, queued_size; int limits; now = UHCI_GET_CURRENT_FRAME (s) & 1023; - if ((unsigned) purb->number_of_packets > 900) + if ((unsigned) urb->number_of_packets > 900) return -EFBIG; - limits = find_iso_limits (purb, &start_limit, &stop_limit); + limits = find_iso_limits (urb, &start_limit, &stop_limit); queued_size = (stop_limit - start_limit) & 1023; - if (purb->transfer_flags & USB_ISO_ASAP) { + if (urb->transfer_flags & USB_ISO_ASAP) { // first iso if (limits) { // 10ms setup should be enough //FIXME! - purb->start_frame = (now + 10) & 1023; + urb->start_frame = (now + 10) & 1023; } else { - purb->start_frame = stop_limit; //seamless linkage + urb->start_frame = stop_limit; //seamless linkage - if (((now - purb->start_frame) & 1023) <= (unsigned) purb->number_of_packets) { - dbg("iso_find_start: warning, ASAP gap, should not happen"); + if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) { + info("iso_find_start: gap in seamless isochronous scheduling"); dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x", - now, purb->start_frame, purb->number_of_packets, purb->pipe); + now, urb->start_frame, urb->number_of_packets, urb->pipe); // The following code is only for debugging purposes... #if 0 { - puhci_t s = (puhci_t) purb->dev->bus->hcpriv; + uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv; struct list_head *p; - purb_t u; + urb_t *u; int a = -1, b = -1; unsigned long flags; @@ -858,7 +889,7 @@ for (; p != &s->urb_list; p = p->next) { u = list_entry (p, urb_t, urb_list); - if (purb->dev != u->dev) + if (urb->dev != u->dev) continue; dbg("urb: pipe 0x%08x status %d start_frame %u number_of_packets %u", u->pipe, u->status, u->start_frame, u->number_of_packets); @@ -871,14 +902,14 @@ spin_unlock_irqrestore(&s->urb_list_lock, flags); } #endif - purb->start_frame = (now + 5) & 1023; // 5ms setup should be enough //FIXME! + urb->start_frame = (now + 5) & 1023; // 5ms setup should be enough //FIXME! //return -EAGAIN; //FIXME } } } else { - purb->start_frame &= 1023; - if (((now - purb->start_frame) & 1023) < (unsigned) purb->number_of_packets) { + urb->start_frame &= 1023; + if (((now - urb->start_frame) & 1023) < (unsigned) urb->number_of_packets) { dbg("iso_find_start: now between start_frame and end"); return -EAGAIN; } @@ -888,10 +919,10 @@ if (limits) return 0; - if (((purb->start_frame - start_limit) & 1023) < queued_size || - ((purb->start_frame + purb->number_of_packets - 1 - start_limit) & 1023) < queued_size) { + if (((urb->start_frame - start_limit) & 1023) < queued_size || + ((urb->start_frame + urb->number_of_packets - 1 - start_limit) & 1023) < queued_size) { dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u", - purb->start_frame, purb->number_of_packets, start_limit, stop_limit); + urb->start_frame, urb->number_of_packets, start_limit, stop_limit); return -EAGAIN; } @@ -902,43 +933,44 @@ // ASAP-flag set implicitely // if period==0, the the transfer is only done once (usb_scsi need this...) -_static int uhci_submit_int_urb (purb_t purb) +_static int uhci_submit_int_urb (urb_t *urb) { - puhci_t s = (puhci_t) purb->dev->bus->hcpriv; - purb_priv_t purb_priv = purb->hcpriv; + uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv; + urb_priv_t *urb_priv = urb->hcpriv; int nint, n, ret; - puhci_desc_t td; + uhci_desc_t *td; int status, destination; int now; int info; - unsigned int pipe = purb->pipe; + unsigned int pipe = urb->pipe; //dbg("SUBMIT INT"); - if (purb->interval < 0 || purb->interval >= 256) + if (urb->interval < 0 || urb->interval >= 256) return -EINVAL; - if (purb->interval == 0) + if (urb->interval == 0) nint = 0; else { for (nint = 0, n = 1; nint <= 8; nint++, n += n) // round interval down to 2^n { - if (purb->interval < n) { - purb->interval = n / 2; + if (urb->interval < n) { + urb->interval = n / 2; break; } } nint--; } - dbg("Rounded interval to %i, chain %i", purb->interval, nint); + + dbg("Rounded interval to %i, chain %i", urb->interval, nint); now = UHCI_GET_CURRENT_FRAME (s) & 1023; - purb->start_frame = now; // remember start frame, just in case... + urb->start_frame = now; // remember start frame, just in case... - purb->number_of_packets = 1; + urb->number_of_packets = 1; // INT allows only one packet - if (purb->transfer_buffer_length > usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe))) + if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe))) return -EINVAL; ret = alloc_td (&td, UHCI_PTR_DEPTH); @@ -947,55 +979,53 @@ return -ENOMEM; status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | - (purb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); + (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); - destination = (purb->pipe & PIPE_DEVEP_MASK) | usb_packetid (purb->pipe) | - (((purb->transfer_buffer_length - 1) & 0x7ff) << 21); + destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) | + (((urb->transfer_buffer_length - 1) & 0x7ff) << 21); - info = destination | (usb_gettoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE); + info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE); - fill_td (td, status, info, virt_to_bus (purb->transfer_buffer)); - list_add_tail (&td->desc_list, &purb_priv->desc_list); + fill_td (td, status, info, virt_to_bus (urb->transfer_buffer)); + list_add_tail (&td->desc_list, &urb_priv->desc_list); - purb->status = USB_ST_URB_PENDING; - queue_urb (s, &purb->urb_list,1); + urb->status = -EINPROGRESS; + queue_urb (s, &urb->urb_list); - insert_td_horizontal (s, s->int_chain[nint], td, UHCI_PTR_DEPTH); // store in INT-TDs + insert_td_horizontal (s, s->int_chain[nint], td); // store in INT-TDs - usb_dotoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)); + usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)); #if 0 - td = tdm[purb->number_of_packets]; + td = tdm[urb->number_of_packets]; fill_td (td, TD_CTRL_IOC, 0, 0); - insert_td_horizontal (s, s->iso_td[(purb->start_frame + (purb->number_of_packets) * purb->interval + 1) & 1023], td, UHCI_PTR_DEPTH); - list_add_tail (&td->desc_list, &purb_priv->desc_list); + insert_td_horizontal (s, s->iso_td[(urb->start_frame + (urb->number_of_packets) * urb->interval + 1) & 1023], td); + list_add_tail (&td->desc_list, &urb_priv->desc_list); #endif return 0; } /*-------------------------------------------------------------------*/ -_static int uhci_submit_iso_urb (purb_t purb) +_static int uhci_submit_iso_urb (urb_t *urb) { - puhci_t s = (puhci_t) purb->dev->bus->hcpriv; - purb_priv_t purb_priv = purb->hcpriv; - int pipe=purb->pipe; - int maxsze = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)); + uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv; + urb_priv_t *urb_priv = urb->hcpriv; + int pipe=urb->pipe; + int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)); int n, ret, last=0; - puhci_desc_t td, *tdm; + uhci_desc_t *td, **tdm; int status, destination; unsigned long flags; - spinlock_t lock; - spin_lock_init (&lock); - spin_lock_irqsave (&lock, flags); // Disable IRQs to schedule all ISO-TDs in time - - ret = iso_find_start (purb); // adjusts purb->start_frame for later use + __save_flags(flags); + __cli(); // Disable IRQs to schedule all ISO-TDs in time + ret = iso_find_start (urb); // adjusts urb->start_frame for later use if (ret) goto err; - tdm = (puhci_desc_t *) kmalloc (purb->number_of_packets * sizeof (puhci_desc_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL); + tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL); if (!tdm) { ret = -ENOMEM; @@ -1003,19 +1033,23 @@ } // First try to get all TDs - for (n = 0; n < purb->number_of_packets; n++) { - dbg("n:%d purb->iso_frame_desc[n].length:%d", n, purb->iso_frame_desc[n].length); - if (!purb->iso_frame_desc[n].length) { + for (n = 0; n < urb->number_of_packets; n++) { + dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length); + if (!urb->iso_frame_desc[n].length) { // allows ISO striping by setting length to zero in iso_descriptor tdm[n] = 0; continue; } - if(purb->iso_frame_desc[n].length > maxsze) { - err("submit_iso: purb->iso_frame_desc[%d].length(%d)>%d",n , purb->iso_frame_desc[n].length, maxsze); + #ifdef ISO_SANITY_CHECK + if(urb->iso_frame_desc[n].length > maxsze) { + err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze); tdm[n] = 0; - continue; + ret=-EINVAL; + goto inval; } + #endif ret = alloc_td (&td, UHCI_PTR_DEPTH); + inval: if (ret) { int i; // Cleanup allocated TDs @@ -1023,20 +1057,19 @@ if (tdm[i]) kfree (tdm[i]); kfree (tdm); - ret = -ENOMEM; goto err; } last=n; tdm[n] = td; } - status = TD_CTRL_ACTIVE | TD_CTRL_IOS; //| (purb->transfer_flags&USB_DISABLE_SPD?0:TD_CTRL_SPD); + status = TD_CTRL_ACTIVE | TD_CTRL_IOS; //| (urb->transfer_flags&USB_DISABLE_SPD?0:TD_CTRL_SPD); - destination = (purb->pipe & PIPE_DEVEP_MASK) | usb_packetid (purb->pipe); + destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe); // Queue all allocated TDs - for (n = 0; n < purb->number_of_packets; n++) { + for (n = 0; n < urb->number_of_packets; n++) { td = tdm[n]; if (!td) continue; @@ -1044,45 +1077,47 @@ if (n == last) status |= TD_CTRL_IOC; - fill_td (td, status, destination | (((purb->iso_frame_desc[n].length - 1) & 0x7ff) << 21), - virt_to_bus (purb->transfer_buffer + purb->iso_frame_desc[n].offset)); - list_add_tail (&td->desc_list, &purb_priv->desc_list); + fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21), + virt_to_bus (urb->transfer_buffer + urb->iso_frame_desc[n].offset)); + list_add_tail (&td->desc_list, &urb_priv->desc_list); if (n == last) { - purb->status = USB_ST_URB_PENDING; - queue_urb (s, &purb->urb_list,1); + urb->status = -EINPROGRESS; + queue_urb (s, &urb->urb_list); } - insert_td_horizontal (s, s->iso_td[(purb->start_frame + n) & 1023], td, UHCI_PTR_DEPTH); // store in iso-tds + insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td); // store in iso-tds //uhci_show_td(td); } kfree (tdm); - dbg("ISO-INT# %i, start %i, now %i", purb->number_of_packets, purb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023); + dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023); ret = 0; err: - spin_unlock_irqrestore (&lock, flags); + __restore_flags(flags); return ret; } /*-------------------------------------------------------------------*/ -_static int search_dev_ep (puhci_t s, purb_t purb) +_static int search_dev_ep (uhci_t *s, urb_t *urb) { unsigned long flags; - struct list_head *p = s->urb_list.next; - purb_t tmp; - unsigned int mask = usb_pipecontrol(purb->pipe) ? (~USB_DIR_IN) : (~0); + struct list_head *p; + urb_t *tmp; + unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0); dbg("search_dev_ep:"); spin_lock_irqsave (&s->urb_list_lock, flags); + p=s->urb_list.next; + for (; p != &s->urb_list; p = p->next) { tmp = list_entry (p, urb_t, urb_list); dbg("urb: %p", tmp); // we can accept this urb if it is not queued at this time // or if non-iso transfer requests should be scheduled for the same device and pipe - if ((!usb_pipeisoc(purb->pipe) && tmp->dev == purb->dev && !((tmp->pipe ^ purb->pipe) & mask)) || - (purb == tmp)) { + if ((!usb_pipeisoc(urb->pipe) && tmp->dev == urb->dev && !((tmp->pipe ^ urb->pipe) & mask)) || + (urb == tmp)) { spin_unlock_irqrestore (&s->urb_list_lock, flags); return 1; // found another urb already queued for processing } @@ -1091,76 +1126,78 @@ return 0; } /*-------------------------------------------------------------------*/ -_static int uhci_submit_urb (purb_t purb) +_static int uhci_submit_urb (urb_t *urb) { - puhci_t s; - purb_priv_t purb_priv; + uhci_t *s; + urb_priv_t *urb_priv; int ret = 0; - if (!purb->dev || !purb->dev->bus) + if (!urb->dev || !urb->dev->bus) return -ENODEV; - s = (puhci_t) purb->dev->bus->hcpriv; - //dbg("submit_urb: %p type %d",purb,usb_pipetype(purb->pipe)); + s = (uhci_t*) urb->dev->bus->hcpriv; + //dbg("submit_urb: %p type %d",urb,usb_pipetype(urb->pipe)); - if (usb_pipedevice (purb->pipe) == s->rh.devnum) - return rh_submit_urb (purb); /* virtual root hub */ + if (usb_pipedevice (urb->pipe) == s->rh.devnum) + return rh_submit_urb (urb); /* virtual root hub */ - usb_inc_dev_use (purb->dev); + usb_inc_dev_use (urb->dev); - if (search_dev_ep (s, purb)) { - usb_dec_dev_use (purb->dev); + if (search_dev_ep (s, urb)) { + usb_dec_dev_use (urb->dev); return -ENXIO; // urb already queued } #ifdef DEBUG_SLAB - purb_priv = kmem_cache_alloc(urb_priv_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL); + urb_priv = kmem_cache_alloc(urb_priv_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL); #else - purb_priv = kmalloc (sizeof (urb_priv_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL); + urb_priv = kmalloc (sizeof (urb_priv_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL); #endif - if (!purb_priv) { - usb_dec_dev_use (purb->dev); + if (!urb_priv) { + usb_dec_dev_use (urb->dev); return -ENOMEM; } - purb->hcpriv = purb_priv; - INIT_LIST_HEAD (&purb_priv->desc_list); - purb_priv->short_control_packet=0; - dbg("submit_urb: scheduling %p", purb); + urb->hcpriv = urb_priv; + INIT_LIST_HEAD (&urb_priv->desc_list); + urb_priv->short_control_packet=0; + dbg("submit_urb: scheduling %p", urb); - switch (usb_pipetype (purb->pipe)) { + switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: - ret = uhci_submit_iso_urb (purb); + ret = uhci_submit_iso_urb (urb); break; case PIPE_INTERRUPT: - ret = uhci_submit_int_urb (purb); + ret = uhci_submit_int_urb (urb); break; case PIPE_CONTROL: - //dump_urb (purb); - ret = uhci_submit_control_urb (purb); + //dump_urb (urb); + ret = uhci_submit_control_urb (urb); break; case PIPE_BULK: - ret = uhci_submit_bulk_urb (purb); + ret = uhci_submit_bulk_urb (urb); break; default: ret = -EINVAL; } dbg("submit_urb: scheduled with ret: %d", ret); - - if (ret != USB_ST_NOERROR) { - usb_dec_dev_use (purb->dev); + + + if (ret != 0) { + usb_dec_dev_use (urb->dev); #ifdef DEBUG_SLAB - kmem_cache_free(urb_priv_kmem, purb_priv); + kmem_cache_free(urb_priv_kmem, urb_priv); #else - kfree (purb_priv); + kfree (urb_priv); #endif return ret; } /* - purb->status = USB_ST_URB_PENDING; - queue_urb (s, &purb->urb_list,1); + urb->status = -EINPROGRESS; + queue_urb (s, &urb->urb_list); + dbg("submit_urb: exit"); */ return 0; @@ -1243,12 +1280,11 @@ /*-------------------------------------------------------------------------*/ /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */ -_static int rh_send_irq (purb_t purb) +_static int rh_send_irq (urb_t *urb) { - int len = 1; int i; - puhci_t uhci = purb->dev->bus->hcpriv; + uhci_t *uhci = urb->dev->bus->hcpriv; unsigned int io_addr = uhci->io_addr; __u16 data = 0; @@ -1257,52 +1293,52 @@ len = (i + 1) / 8 + 1; } - *(__u16 *) purb->transfer_buffer = cpu_to_le16 (data); - purb->actual_length = len; - purb->status = USB_ST_NOERROR; - + *(__u16 *) urb->transfer_buffer = cpu_to_le16 (data); + urb->actual_length = len; + urb->status = 0; + if ((data > 0) && (uhci->rh.send != 0)) { dbg("Root-Hub INT complete: port1: %x port2: %x data: %x", inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data); - purb->complete (purb); + urb->complete (urb); } - return USB_ST_NOERROR; + return 0; } /*-------------------------------------------------------------------------*/ /* Virtual Root Hub INTs are polled by this timer every "intervall" ms */ -_static int rh_init_int_timer (purb_t purb); +_static int rh_init_int_timer (urb_t *urb); _static void rh_int_timer_do (unsigned long ptr) { int len; - purb_t purb = (purb_t) ptr; - puhci_t uhci = purb->dev->bus->hcpriv; + urb_t *urb = (urb_t*) ptr; + uhci_t *uhci = urb->dev->bus->hcpriv; if (uhci->rh.send) { - len = rh_send_irq (purb); + len = rh_send_irq (urb); if (len > 0) { - purb->actual_length = len; - if (purb->complete) - purb->complete (purb); + urb->actual_length = len; + if (urb->complete) + urb->complete (urb); } } - rh_init_int_timer (purb); + rh_init_int_timer (urb); } /*-------------------------------------------------------------------------*/ /* Root Hub INTs are polled by this timer */ -_static int rh_init_int_timer (purb_t purb) +_static int rh_init_int_timer (urb_t *urb) { - puhci_t uhci = purb->dev->bus->hcpriv; + uhci_t *uhci = urb->dev->bus->hcpriv; - uhci->rh.interval = purb->interval; + uhci->rh.interval = urb->interval; init_timer (&uhci->rh.rh_int_timer); uhci->rh.rh_int_timer.function = rh_int_timer_do; - uhci->rh.rh_int_timer.data = (unsigned long) purb; - uhci->rh.rh_int_timer.expires = jiffies + (HZ * (purb->interval < 30 ? 30 : purb->interval)) / 1000; + uhci->rh.rh_int_timer.data = (unsigned long) urb; + uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000; add_timer (&uhci->rh.rh_int_timer); return 0; @@ -1328,17 +1364,17 @@ *************************/ -_static int rh_submit_urb (purb_t purb) +_static int rh_submit_urb (urb_t *urb) { - struct usb_device *usb_dev = purb->dev; - puhci_t uhci = usb_dev->bus->hcpriv; - unsigned int pipe = purb->pipe; - devrequest *cmd = (devrequest *) purb->setup_packet; - void *data = purb->transfer_buffer; - int leni = purb->transfer_buffer_length; + struct usb_device *usb_dev = urb->dev; + uhci_t *uhci = usb_dev->bus->hcpriv; + unsigned int pipe = urb->pipe; + devrequest *cmd = (devrequest *) urb->setup_packet; + void *data = urb->transfer_buffer; + int leni = urb->transfer_buffer_length; int len = 0; int status = 0; - int stat = USB_ST_NOERROR; + int stat = 0; int i; unsigned int io_addr = uhci->io_addr; __u16 cstatus; @@ -1349,13 +1385,13 @@ __u16 wLength; if (usb_pipetype (pipe) == PIPE_INTERRUPT) { - dbg("Root-Hub submit IRQ: every %d ms", purb->interval); - uhci->rh.urb = purb; + dbg("Root-Hub submit IRQ: every %d ms", urb->interval); + uhci->rh.urb = urb; uhci->rh.send = 1; - uhci->rh.interval = purb->interval; - rh_init_int_timer (purb); + uhci->rh.interval = urb->interval; + rh_init_int_timer (urb); - return USB_ST_NOERROR; + return 0; } @@ -1455,12 +1491,12 @@ OK (0); case (RH_PORT_RESET): SET_RH_PORTSTAT (USBPORTSC_PR); - wait_ms (10); + uhci_wait_ms (10); uhci->rh.c_p_r[wIndex - 1] = 1; CLR_RH_PORTSTAT (USBPORTSC_PR); udelay (10); SET_RH_PORTSTAT (USBPORTSC_PE); - wait_ms (10); + uhci_wait_ms (10); SET_RH_PORTSTAT (0xa); OK (0); case (RH_PORT_POWER): @@ -1510,17 +1546,17 @@ dbg("Root-Hub stat port1: %x port2: %x", inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2)); - purb->actual_length = len; - purb->status = stat; - if (purb->complete) - purb->complete (purb); - return USB_ST_NOERROR; + urb->actual_length = len; + urb->status = stat; + if (urb->complete) + urb->complete (urb); + return 0; } /*-------------------------------------------------------------------------*/ -_static int rh_unlink_urb (purb_t purb) +_static int rh_unlink_urb (urb_t *urb) { - puhci_t uhci = purb->dev->bus->hcpriv; + uhci_t *uhci = urb->dev->bus->hcpriv; dbg("Root-Hub unlink IRQ"); uhci->rh.send = 0; @@ -1538,7 +1574,7 @@ _static int uhci_map_status (int status, int dir_out) { if (!status) - return USB_ST_NOERROR; + return 0; if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */ return -EPROTO; if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */ @@ -1556,7 +1592,7 @@ if (status & TD_CTRL_STALLED) /* Stalled */ return -EPIPE; if (status & TD_CTRL_ACTIVE) /* Active */ - return USB_ST_NOERROR; + return 0; return -EPROTO; } @@ -1569,8 +1605,42 @@ return 0; } +_static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all) +{ + unsigned long flags; + struct list_head *p; + struct list_head *p2; + urb_t *urb; + + spin_lock_irqsave (&s->urb_list_lock, flags); + p = s->urb_list.prev; + while (p != &s->urb_list) { + p2 = p; + p = p->prev; + urb = list_entry (p2, urb_t, urb_list); + dbg("urb: %p", urb); + if (remove_all || (usb_dev == urb->dev)) { + warn("forced removing of queued URB %p due to disconnect",urb); + uhci_unlink_urb(urb); + urb->dev = NULL; // avoid further processing of this URB + } + } + spin_unlock_irqrestore (&s->urb_list_lock, flags); +} + _static int uhci_free_dev (struct usb_device *usb_dev) { + uhci_t *s; + + dbg("uhci_free_dev"); + + if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv) + return -EINVAL; + + s=(uhci_t*) usb_dev->bus->hcpriv; + + uhci_unlink_urbs(s, usb_dev, 0); + return 0; } @@ -1581,7 +1651,7 @@ */ _static int uhci_get_current_frame_number (struct usb_device *usb_dev) { - return UHCI_GET_CURRENT_FRAME ((puhci_t) usb_dev->bus->hcpriv); + return UHCI_GET_CURRENT_FRAME ((uhci_t*) usb_dev->bus->hcpriv); } struct usb_operations uhci_device_operations = @@ -1603,22 +1673,23 @@ * when the transfered length fits exactly in maxsze-packets. A bit * more intelligence is needed to detect this and finish without error. */ -_static int process_transfer (puhci_t s, purb_t purb) + +_static int process_transfer (uhci_t *s, urb_t *urb) { - int ret = USB_ST_NOERROR; - purb_priv_t purb_priv = purb->hcpriv; - struct list_head *qhl = purb_priv->desc_list.next; - puhci_desc_t qh = list_entry (qhl, uhci_desc_t, desc_list); + int ret = 0; + urb_priv_t *urb_priv = urb->hcpriv; + struct list_head *qhl = urb_priv->desc_list.next; + uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list); struct list_head *p = qh->vertical.next; - puhci_desc_t desc= list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list); - puhci_desc_t last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical); - int data_toggle = usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe)); // save initial data_toggle + uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list); + uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical); + int data_toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); // save initial data_toggle // extracted and remapped info from TD int maxlength; int actual_length; - int status = USB_ST_NOERROR; + int status = 0; dbg("process_transfer: urb contains bulk/control request"); @@ -1628,11 +1699,11 @@ status stage is completed */ #if 1 - if (purb_priv->short_control_packet && + if (urb_priv->short_control_packet && ((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & TD_CTRL_ACTIVE)))) goto transfer_finished; #endif - purb->actual_length=0; + urb->actual_length=0; for (; p != &qh->vertical; p = p->next) { desc = list_entry (p, uhci_desc_t, vertical); @@ -1643,24 +1714,24 @@ // extract transfer parameters from TD actual_length = (desc->hw.td.status + 1) & 0x7ff; maxlength = (((desc->hw.td.info >> 21) & 0x7ff) + 1) & 0x7ff; - status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe)); + status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe)); // see if EP is stalled if (status == -EPIPE) { // set up stalled condition - usb_endpoint_halt (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe)); + usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); } // if any error occured stop processing of further TDs - if (status != USB_ST_NOERROR) { + if (status != 0) { // only set ret if status returned an error uhci_show_td (desc); ret = status; - purb->error_count++; + urb->error_count++; break; } else if ((desc->hw.td.info & 0xff) != USB_PID_SETUP) - purb->actual_length += actual_length; + urb->actual_length += actual_length; #if 0 // if (i++==0) @@ -1669,21 +1740,21 @@ // got less data than requested if ( (actual_length < maxlength)) { - if (purb->transfer_flags & USB_DISABLE_SPD) { - ret = USB_ST_SHORT_PACKET; // treat as real error + if (urb->transfer_flags & USB_DISABLE_SPD) { + ret = -EREMOTEIO; // treat as real error dbg("process_transfer: SPD!!"); break; // exit after this TD because SP was detected } // short read during control-IN: re-start status stage - if ((usb_pipetype (purb->pipe) == PIPE_CONTROL)) { + if ((usb_pipetype (urb->pipe) == PIPE_CONTROL)) { if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) { qh->hw.qh.element = virt_to_bus (last_desc); // re-trigger status stage dbg("short packet during control transfer, retrigger status stage @ %p",last_desc); uhci_show_td (desc); uhci_show_td (last_desc); - purb_priv->short_control_packet=1; + urb_priv->short_control_packet=1; return 0; } } @@ -1696,33 +1767,23 @@ //dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, desc->hw.td.status,status, data_toggle); } - usb_settoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe), !data_toggle); + usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle); transfer_finished: - /* APC BackUPS Pro kludge */ - /* It tries to send all of the descriptor instead of */ - /* the amount we requested */ - if (desc->hw.td.status & TD_CTRL_IOC && - status & TD_CTRL_ACTIVE && - status & TD_CTRL_NAK ) - { - dbg("APS WORKAROUND"); - ret=0; - status=0; - } - unlink_qh (s, qh); - delete_qh (s, qh); + //delete_qh (s, qh); + qh->last_used=UHCI_GET_CURRENT_FRAME(s); + list_add_tail (&qh->horizontal, &s->free_desc); // mark for later deletion + + urb->status = status; - purb->status = status; - dbg("process_transfer: urb %p, wanted len %d, len %d status %x err %d", - purb,purb->transfer_buffer_length,purb->actual_length, purb->status, purb->error_count); + urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count); //dbg("process_transfer: exit"); #if 0 - if (purb->actual_length){ + if (urb->actual_length){ char *uu; - uu=purb->transfer_buffer; + uu=urb->transfer_buffer; dbg("%x %x %x %x %x %x %x %x", *uu,*(uu+1),*(uu+2),*(uu+3),*(uu+4),*(uu+5),*(uu+6),*(uu+7)); } @@ -1730,19 +1791,19 @@ return ret; } -_static int process_interrupt (puhci_t s, purb_t purb) +_static int process_interrupt (uhci_t *s, urb_t *urb) { - int i, ret = USB_ST_URB_PENDING; - purb_priv_t purb_priv = purb->hcpriv; - struct list_head *p = purb_priv->desc_list.next; - puhci_desc_t desc = list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list); + int i, ret = -EINPROGRESS; + urb_priv_t *urb_priv = urb->hcpriv; + struct list_head *p = urb_priv->desc_list.next; + uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list); int actual_length; - int status = USB_ST_NOERROR; + int status = 0; //dbg("urb contains interrupt request"); - for (i = 0; p != &purb_priv->desc_list; p = p->next, i++) // Maybe we allow more than one TD later ;-) + for (i = 0; p != &urb_priv->desc_list; p = p->next, i++) // Maybe we allow more than one TD later ;-) { desc = list_entry (p, uhci_desc_t, desc_list); @@ -1759,47 +1820,54 @@ // extract transfer parameters from TD actual_length = (desc->hw.td.status + 1) & 0x7ff; - status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe)); + status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe)); // see if EP is stalled if (status == -EPIPE) { // set up stalled condition - usb_endpoint_halt (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe)); + usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); } // if any error occured: ignore this td, and continue - if (status != USB_ST_NOERROR) { + if (status != 0) { uhci_show_td (desc); - purb->error_count++; + urb->error_count++; goto recycle; } else - purb->actual_length = actual_length; + urb->actual_length = actual_length; // FIXME: SPD? recycle: - if (purb->complete) { + if (urb->complete) { //dbg("process_interrupt: calling completion, status %i",status); - purb->status = status; - purb->complete ((struct urb *) purb); - purb->status = USB_ST_URB_PENDING; + urb->status = status; + + spin_unlock(&s->urb_list_lock); + + urb->complete ((struct urb *) urb); + + spin_lock(&s->urb_list_lock); + + urb->status = -EINPROGRESS; } // Recycle INT-TD if interval!=0, else mark TD as one-shot - if (purb->interval) { + if (urb->interval) { + desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE); if (status==0) { - desc->hw.td.info |= (usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe), - usb_pipeout (purb->pipe)) << TD_TOKEN_TOGGLE); - usb_dotoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe)); + desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE); + usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); } else { - desc->hw.td.info |= (!usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe), - usb_pipeout (purb->pipe)) << TD_TOKEN_TOGGLE); + desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE); } - desc->hw.td.status= (purb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | - (purb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); - wmb(); + desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | + (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27); + mb(); } else { desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD @@ -1810,23 +1878,23 @@ } -_static int process_iso (puhci_t s, purb_t purb) +_static int process_iso (uhci_t *s, urb_t *urb) { int i; - int ret = USB_ST_NOERROR; - purb_priv_t purb_priv = purb->hcpriv; - struct list_head *p = purb_priv->desc_list.next; - puhci_desc_t desc = list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list); + int ret = 0; + urb_priv_t *urb_priv = urb->hcpriv; + struct list_head *p = urb_priv->desc_list.next; + uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list); dbg("urb contains iso request"); if (desc->hw.td.status & TD_CTRL_ACTIVE) - return USB_ST_PARTIAL_ERROR; // last TD not finished + return -EXDEV; // last TD not finished - purb->error_count = 0; - purb->actual_length = 0; - purb->status = USB_ST_NOERROR; + urb->error_count = 0; + urb->actual_length = 0; + urb->status = 0; - for (i = 0; p != &purb_priv->desc_list; p = p->next, i++) { + for (i = 0; p != &urb_priv->desc_list; p = p->next, i++) { desc = list_entry (p, uhci_desc_t, desc_list); //uhci_show_td(desc); @@ -1834,40 +1902,40 @@ // means we have completed the last TD, but not the TDs before desc->hw.td.status &= ~TD_CTRL_ACTIVE; dbg("TD still active (%x)- grrr. paranoia!", desc->hw.td.status); - ret = USB_ST_PARTIAL_ERROR; - purb->iso_frame_desc[i].status = ret; - unlink_td (s, desc); + ret = -EXDEV; + urb->iso_frame_desc[i].status = ret; + unlink_td (s, desc, 1); // FIXME: immediate deletion may be dangerous goto err; } - unlink_td (s, desc); + unlink_td (s, desc, 1); - if (purb->number_of_packets <= i) { - dbg("purb->number_of_packets (%d)<=(%d)", purb->number_of_packets, i); - ret = USB_ST_URB_INVALID_ERROR; + if (urb->number_of_packets <= i) { + dbg("urb->number_of_packets (%d)<=(%d)", urb->number_of_packets, i); + ret = -EINVAL; goto err; } - if (purb->iso_frame_desc[i].offset + purb->transfer_buffer != bus_to_virt (desc->hw.td.buffer)) { + if (urb->iso_frame_desc[i].offset + urb->transfer_buffer != bus_to_virt (desc->hw.td.buffer)) { // Hm, something really weird is going on - dbg("Pointer Paranoia: %p!=%p", purb->iso_frame_desc[i].offset + purb->transfer_buffer, bus_to_virt (desc->hw.td.buffer)); - ret = USB_ST_URB_INVALID_ERROR; - purb->iso_frame_desc[i].status = ret; + dbg("Pointer Paranoia: %p!=%p", urb->iso_frame_desc[i].offset + urb->transfer_buffer, bus_to_virt (desc->hw.td.buffer)); + ret = -EINVAL; + urb->iso_frame_desc[i].status = ret; goto err; } - purb->iso_frame_desc[i].actual_length = (desc->hw.td.status + 1) & 0x7ff; - purb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe)); - purb->actual_length += purb->iso_frame_desc[i].actual_length; + urb->iso_frame_desc[i].actual_length = (desc->hw.td.status + 1) & 0x7ff; + urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe)); + urb->actual_length += urb->iso_frame_desc[i].actual_length; err: - if (purb->iso_frame_desc[i].status != USB_ST_NOERROR) { - purb->error_count++; - purb->status = purb->iso_frame_desc[i].status; + if (urb->iso_frame_desc[i].status != 0) { + urb->error_count++; + urb->status = urb->iso_frame_desc[i].status; } dbg("process_iso: len:%d status:%x", - purb->iso_frame_desc[i].length, purb->iso_frame_desc[i].status); + urb->iso_frame_desc[i].length, urb->iso_frame_desc[i].status); delete_desc (desc); list_del (p); @@ -1877,83 +1945,87 @@ } -_static int process_urb (puhci_t s, struct list_head *p) +_static int process_urb (uhci_t *s, struct list_head *p) { - int ret = USB_ST_NOERROR; - purb_t purb; + int ret = 0; + urb_t *urb; - spin_lock(&s->urb_list_lock); - purb=list_entry (p, urb_t, urb_list); - dbg("found queued urb: %p", purb); - switch (usb_pipetype (purb->pipe)) { + urb=list_entry (p, urb_t, urb_list); + dbg("found queued urb: %p", urb); + + switch (usb_pipetype (urb->pipe)) { case PIPE_CONTROL: case PIPE_BULK: - ret = process_transfer (s, purb); + ret = process_transfer (s, urb); break; case PIPE_ISOCHRONOUS: - ret = process_iso (s, purb); + ret = process_iso (s, urb); break; case PIPE_INTERRUPT: - ret = process_interrupt (s, purb); + ret = process_interrupt (s, urb); break; } - spin_unlock(&s->urb_list_lock); - - if (purb->status != USB_ST_URB_PENDING) { + if (urb->status != -EINPROGRESS) { int proceed = 0; - dbg("dequeued urb: %p", purb); - dequeue_urb (s, p, 1); + + dbg("dequeued urb: %p", urb); + dequeue_urb (s, p); #ifdef DEBUG_SLAB - kmem_cache_free(urb_priv_kmem, purb->hcpriv); + kmem_cache_free(urb_priv_kmem, urb->hcpriv); #else - kfree (purb->hcpriv); + kfree (urb->hcpriv); #endif - if ((usb_pipetype (purb->pipe) != PIPE_INTERRUPT)) { - purb_t tmp = purb->next; // pointer to first urb + if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) { + urb_t *tmp = urb->next; // pointer to first urb int is_ring = 0; - if (purb->next) { + if (urb->next) { do { - if (tmp->status != USB_ST_URB_PENDING) { + if (tmp->status != -EINPROGRESS) { proceed = 1; break; } tmp = tmp->next; } - while (tmp != NULL && tmp != purb->next); - if (tmp == purb->next) + while (tmp != NULL && tmp != urb->next); + if (tmp == urb->next) is_ring = 1; } + spin_unlock(&s->urb_list_lock); + // In case you need the current URB status for your completion handler - if (purb->complete && (!proceed || (purb->transfer_flags & USB_URB_EARLY_COMPLETE))) { + if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) { dbg("process_transfer: calling early completion"); - purb->complete ((struct urb *) purb); - if (!proceed && is_ring && (purb->status != USB_ST_URB_KILLED)) - uhci_submit_urb (purb); + urb->complete ((struct urb *) urb); + if (!proceed && is_ring && (urb->status != -ENOENT)) + uhci_submit_urb (urb); } - if (proceed && purb->next) { + if (proceed && urb->next) { // if there are linked urbs - handle submitting of them right now. - tmp = purb->next; // pointer to first urb + tmp = urb->next; // pointer to first urb do { - if ((tmp->status != USB_ST_URB_PENDING) && (tmp->status != USB_ST_URB_KILLED) && uhci_submit_urb (tmp) != USB_ST_NOERROR) + if ((tmp->status != -EINPROGRESS) && (tmp->status != -ENOENT) && uhci_submit_urb (tmp) != 0) break; tmp = tmp->next; } - while (tmp != NULL && tmp != purb->next); // submit until we reach NULL or our own pointer or submit fails + while (tmp != NULL && tmp != urb->next); // submit until we reach NULL or our own pointer or submit fails - if (purb->complete && !(purb->transfer_flags & USB_URB_EARLY_COMPLETE)) { + if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE)) { dbg("process_transfer: calling completion"); - purb->complete ((struct urb *) purb); + urb->complete ((struct urb *) urb); } } - usb_dec_dev_use (purb->dev); + + spin_lock(&s->urb_list_lock); + + usb_dec_dev_use (urb->dev); } } @@ -1962,7 +2034,7 @@ _static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs) { - puhci_t s = __uhci; + uhci_t *s = __uhci; unsigned int io_addr = s->io_addr; unsigned short status; struct list_head *p, *p2; @@ -1980,8 +2052,9 @@ dbg("interrupt"); if (status != 1) { - warn("interrupt, status %x", status); - + warn("interrupt, status %x, frame# %i", status, + UHCI_GET_CURRENT_FRAME(s)); + //uhci_show_queue(s->control_chain); // remove host controller halted state if ((status&0x20) && (s->running)) { // more to be done - check TDs for invalid entries @@ -2000,39 +2073,42 @@ * - Thomas Sailer */ - spin_lock(&s->unlink_urb_lock); spin_lock (&s->urb_list_lock); - p = s->urb_list.prev; - spin_unlock (&s->urb_list_lock); +restart: + s->unlink_urb_done=0; + p = s->urb_list.prev; while (p != &s->urb_list) { p2 = p; p = p->prev; process_urb (s, p2); + if(s->unlink_urb_done) + { + s->unlink_urb_done=0; + goto restart; + } } - - spin_unlock(&s->unlink_urb_lock); + spin_unlock (&s->urb_list_lock); + clean_descs(s,0); outw (status, io_addr + USBSTS); -#ifdef __alpha - mb (); // ? -#endif - dbg("done\n\n"); + + dbg("done"); } -_static void reset_hc (puhci_t s) +_static void reset_hc (uhci_t *s) { unsigned int io_addr = s->io_addr; s->apm_state = 0; /* Global reset for 50ms */ outw (USBCMD_GRESET, io_addr + USBCMD); - wait_ms (50); + uhci_wait_ms (50); outw (0, io_addr + USBCMD); - wait_ms (10); + uhci_wait_ms (10); } -_static void start_hc (puhci_t s) +_static void start_hc (uhci_t *s) { unsigned int io_addr = s->io_addr; int timeout = 1000; @@ -2065,13 +2141,17 @@ s->running = 1; } -_static void __exit uhci_cleanup_dev(puhci_t s) +_static void __exit uhci_cleanup_dev(uhci_t *s) { struct usb_device *root_hub = s->bus->root_hub; + if (root_hub) usb_disconnect (&root_hub); + uhci_unlink_urbs(s, 0, 1); // Forced unlink of remaining URBs + usb_deregister_bus (s->bus); + s->running = 0; reset_hc (s); release_region (s->io_addr, s->io_size); @@ -2079,10 +2159,9 @@ usb_free_bus (s->bus); cleanup_skel (s); kfree (s); - } -_static int __init uhci_start_usb (puhci_t s) +_static int __init uhci_start_usb (uhci_t *s) { /* start it up */ /* connect the virtual root hub */ struct usb_device *usb_dev; @@ -2102,21 +2181,22 @@ return 0; } -_static int __init alloc_uhci (int irq, unsigned int io_addr, unsigned int io_size) +_static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size) { - puhci_t s; + uhci_t *s; struct usb_bus *bus; + struct pm_dev *pmdev; s = kmalloc (sizeof (uhci_t), GFP_KERNEL); if (!s) return -1; memset (s, 0, sizeof (uhci_t)); + INIT_LIST_HEAD (&s->free_desc); INIT_LIST_HEAD (&s->urb_list); spin_lock_init (&s->urb_list_lock); spin_lock_init (&s->qh_lock); spin_lock_init (&s->td_lock); - spin_lock_init (&s->unlink_urb_lock); s->irq = -1; s->io_addr = io_addr; s->io_size = io_size; @@ -2146,7 +2226,7 @@ if (!(portstatus & 0x0080)) break; } - dbg("Detected %d ports", s->maxports); + warn("Detected %d ports", s->maxports); /* This is experimental so anything less than 2 or greater than 8 is */ /* something weird and we'll ignore it */ @@ -2185,10 +2265,14 @@ uhci_cleanup_dev(s); return -1; } - + //chain new uhci device into global list devs = s; + pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(dev), handle_pm_event); + if (pmdev) + pmdev->data = s; + return 0; } @@ -2217,47 +2301,27 @@ break; /* disable legacy emulation */ pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT); - - return alloc_uhci(dev->irq, io_addr, io_size); + return alloc_uhci(dev, dev->irq, io_addr, io_size); } return -1; } -#ifdef CONFIG_APM -_static int handle_apm_event (apm_event_t event) +_static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data) { - static int down = 0; - puhci_t s = devs; - dbg("handle_apm_event(%d)", event); - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - if (down) { - dbg("received extra suspend event"); - break; - } - while (s) { + uhci_t *s = (uhci_t*) dev->data; + dbg("handle_apm_event(%d)", rqst); + if (s) { + switch (rqst) { + case PM_SUSPEND: reset_hc (s); - s = s->next; - } - down = 1; - break; - case APM_NORMAL_RESUME: - case APM_CRITICAL_RESUME: - if (!down) { - dbg("received bogus resume event"); break; - } - down = 0; - while (s) { + case PM_RESUME: start_hc (s); - s = s->next; + break; } - break; } return 0; } -#endif int __init uhci_init (void) { @@ -2267,26 +2331,15 @@ int i=0; #ifdef DEBUG_SLAB - char *slabname=kmalloc(16, GFP_KERNEL); - - if(!slabname) - return -ENOMEM; - strcpy(slabname, "uhci_desc"); - uhci_desc_kmem = kmem_cache_create(slabname, sizeof(uhci_desc_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + uhci_desc_kmem = kmem_cache_create("uhci_desc", sizeof(uhci_desc_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if(!uhci_desc_kmem) { err("kmem_cache_create for uhci_desc failed (out of memory)"); return -ENOMEM; } - slabname=kmalloc(16, GFP_KERNEL); - - if(!slabname) - return -ENOMEM; - - strcpy(slabname, "urb_priv"); - urb_priv_kmem = kmem_cache_create(slabname, sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + urb_priv_kmem = kmem_cache_create("urb_priv", sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if(!urb_priv_kmem) { err("kmem_cache_create for urb_priv_t failed (out of memory)"); @@ -2319,26 +2372,26 @@ if (!retval) i++; - } -#ifdef CONFIG_APM - if(i) - apm_register_callback (&handle_apm_event); -#endif return retval; } void __exit uhci_cleanup (void) { - puhci_t s; + uhci_t *s; while ((s = devs)) { devs = devs->next; uhci_cleanup_dev(s); } #ifdef DEBUG_SLAB - kmem_cache_shrink(uhci_desc_kmem); - kmem_cache_shrink(urb_priv_kmem); + + + if(kmem_cache_destroy(uhci_desc_kmem)) + err("uhci_desc_kmem remained"); + + if(kmem_cache_destroy(urb_priv_kmem)) + err("urb_priv_kmem remained"); #endif } @@ -2350,9 +2403,7 @@ void cleanup_module (void) { -#ifdef CONFIG_APM - apm_unregister_callback (&handle_apm_event); -#endif + pm_unregister_all (handle_pm_event); uhci_cleanup (); } diff -u --recursive --new-file v2.3.42/linux/drivers/usb/usb-uhci.h linux/drivers/usb/usb-uhci.h --- v2.3.42/linux/drivers/usb/usb-uhci.h Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/usb-uhci.h Mon Feb 7 19:15:59 2000 @@ -2,10 +2,21 @@ #define __LINUX_UHCI_H /* - $Id: usb-uhci.h,v 1.31 2000/01/15 22:02:30 acher Exp $ + $Id: usb-uhci.h,v 1.39 2000/02/05 20:25:27 acher Exp $ */ #define MODNAME "usb-uhci" -#define VERSTR "version v1.169 time " __TIME__ " " __DATE__ +#define VERSTR "version v1.184 time " __TIME__ " " __DATE__ + +static __inline__ void uhci_wait_ms(unsigned int ms) +{ + if(!in_interrupt()) + { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1 + ms * HZ / 1000); + } + else + mdelay(ms); +} /* Command register */ #define USBCMD 0 @@ -56,6 +67,7 @@ #define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ #define UHCI_NULL_DATA_SIZE 0x7ff /* for UHCI controller TD */ +#define UHCI_PID 0xff /* PID MASK */ #define UHCI_PTR_BITS 0x000F #define UHCI_PTR_TERM 0x0001 @@ -137,6 +149,7 @@ struct list_head horizontal; struct list_head vertical; struct list_head desc_list; + int last_used; } uhci_desc_t, *puhci_desc_t; typedef struct { @@ -170,16 +183,17 @@ spinlock_t urb_list_lock; // lock to keep consistency + int unlink_urb_done; + struct usb_bus *bus; // our bus - spinlock_t unlink_urb_lock; // lock for unlink_urb - __u32 *framelist; uhci_desc_t **iso_td; uhci_desc_t *int_chain[8]; uhci_desc_t *control_chain; uhci_desc_t *bulk_chain; uhci_desc_t *chain_end; + struct list_head free_desc; spinlock_t qh_lock; spinlock_t td_lock; struct virt_root_hub rh; //private data of the virtual root hub diff -u --recursive --new-file v2.3.42/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.42/linux/drivers/usb/usb.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/usb.c Wed Feb 9 11:42:35 2000 @@ -1363,7 +1363,7 @@ static void usb_set_maxpacket(struct usb_device *dev) { - int i, j; + int i, j, b; struct usb_interface *ifp; for (i=0; iactconfig->bNumInterfaces; i++) { @@ -1375,12 +1375,15 @@ int e; for (e=0; ebNumEndpoints; e++) { - if (usb_endpoint_out(ep[e].bEndpointAddress)) - dev->epmaxpacketout[ep[e].bEndpointAddress & 0x0f] = - ep[e].wMaxPacketSize; - else - dev->epmaxpacketin [ep[e].bEndpointAddress & 0x0f] = - ep[e].wMaxPacketSize; + b = ep[e].bEndpointAddress & 0x0f; + if (usb_endpoint_out(ep[e].bEndpointAddress)) { + if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b]) + dev->epmaxpacketout[b] = ep[e].wMaxPacketSize; + } + else { + if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b]) + dev->epmaxpacketin [b] = ep[e].wMaxPacketSize; + } } } } @@ -1756,16 +1759,7 @@ } static struct file_operations usb_fops = { - NULL, /* seek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* readdir */ - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* mmap */ - usb_open, - NULL, /* flush */ - NULL /* release */ + open: usb_open, }; int usb_major_init(void) diff -u --recursive --new-file v2.3.42/linux/drivers/usb/usb_storage.h linux/drivers/usb/usb_storage.h --- v2.3.42/linux/drivers/usb/usb_storage.h Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/usb_storage.h Mon Feb 7 19:12:22 2000 @@ -72,7 +72,7 @@ __u8 Filler[18]; }; -#define US_BULK_CS_WRAP_LEN 31 +#define US_BULK_CS_WRAP_LEN 13 #define US_BULK_CS_SIGN 0x53425355 #define US_BULK_STAT_OK 0 #define US_BULK_STAT_FAIL 1 diff -u --recursive --new-file v2.3.42/linux/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c --- v2.3.42/linux/drivers/usb/usbkbd.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/usbkbd.c Mon Feb 7 19:14:45 2000 @@ -49,7 +49,7 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 134,130,132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 42, 56,125, 97, 54,100,126 }; diff -u --recursive --new-file v2.3.42/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c --- v2.3.42/linux/drivers/video/acornfb.c Tue Dec 7 09:32:46 1999 +++ linux/drivers/video/acornfb.c Sun Feb 6 17:45:25 2000 @@ -575,14 +575,16 @@ break; } - if (min_size > size) { - /* - * failed, use ypan - */ - size = current_par.screen_size; - var->yres_virtual = size / (font_line_len / fontht); - } else - var->yres_virtual = nr_y * fontht; + if (var->accel_flags & FB_ACCELF_TEXT) { + if (min_size > size) { + /* + * failed, use ypan + */ + size = current_par.screen_size; + var->yres_virtual = size / (font_line_len / fontht); + } else + var->yres_virtual = nr_y * fontht; + } current_par.screen_end = current_par.screen_base_p + size; @@ -1283,7 +1285,7 @@ vmode: FB_VMODE_NONINTERLACED }; -static void __init +static void __init acornfb_init_fbinfo(void) { static int first = 1; @@ -1325,6 +1327,7 @@ init_var.height = -1; init_var.width = -1; init_var.vmode = FB_VMODE_NONINTERLACED; + init_var.accel_flags = FB_ACCELF_TEXT; current_par.dram_size = 0; current_par.montype = -1; @@ -1363,15 +1366,17 @@ * size can optionally be followed by 'M' or 'K' for * MB or KB respectively. */ -static void __init +static void __init acornfb_parse_font(char *opt) { strcpy(fb_info.fontname, opt); } -static void __init +static void __init acornfb_parse_mon(char *opt) { + current_par.montype = -2; + fb_info.monspecs.hfmin = simple_strtoul(opt, &opt, 0); if (*opt == '-') fb_info.monspecs.hfmax = simple_strtoul(opt + 1, &opt, 0); @@ -1403,7 +1408,7 @@ init_var.height = simple_strtoul(opt + 1, NULL, 0); } -static void __init +static void __init acornfb_parse_montype(char *opt) { current_par.montype = -2; @@ -1445,7 +1450,7 @@ } } -static void __init +static void __init acornfb_parse_dram(char *opt) { unsigned int size; @@ -1479,7 +1484,7 @@ { NULL, NULL } }; -int __init +int __init acornfb_setup(char *options) { struct options *optp; @@ -1517,7 +1522,7 @@ * Detect type of monitor connected * For now, we just assume SVGA */ -static int __init +static int __init acornfb_detect_monitortype(void) { return 4; @@ -1554,7 +1559,7 @@ printk("acornfb: freed %dK memory\n", mb_freed); } -int __init +int __init acornfb_init(void) { unsigned long size; @@ -1566,10 +1571,11 @@ if (current_par.montype == -1) current_par.montype = acornfb_detect_monitortype(); - if (current_par.montype < 0 || current_par.montype > NR_MONTYPES) + if (current_par.montype == -1 || current_par.montype > NR_MONTYPES) current_par.montype = 4; - fb_info.monspecs = monspecs[current_par.montype]; + if (current_par.montype > 0) + fb_info.monspecs = monspecs[current_par.montype]; fb_info.monspecs.dpms = current_par.dpms; /* @@ -1642,7 +1648,7 @@ for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE) free_page(page); current_par.screen_base_p = - virt_to_phys(current_par.screen_base); + virt_to_phys((void *)current_par.screen_base); } #endif #if defined(HAS_VIDC) diff -u --recursive --new-file v2.3.42/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c --- v2.3.42/linux/drivers/video/aty128fb.c Thu Jan 6 12:57:48 2000 +++ linux/drivers/video/aty128fb.c Tue Feb 8 12:01:59 2000 @@ -1,22 +1,30 @@ -/* $Id: aty128fb.c,v 1.1 1999/10/12 11:00:43 geert Exp $ +/* $Id: aty128fb.c,v 1.1.1.1.36.1 1999/12/11 09:03:05 Exp $ * linux/drivers/video/aty128fb.c -- Frame buffer device for ATI Rage128 * - * Copyright (C) Summer 1999, Anthony Tong + * Copyright (C) 1999-2000, Anthony Tong * - * Brad Douglas + * Brad Douglas * - x86 support * - MTRR * - Probe ROM for PLL + * - modedb + * + * Ani Joshi / Jeff Garzik + * - Code cleanup * * Based off of Geert's atyfb.c and vfb.c. * * TODO: * - panning - * - fix 15/16 bpp on big endian arch's * - monitor sensing (DDC) + * - virtual display * - other platform support (only ppc/x86 supported) - * - PPLL_REF_DIV & XTALIN calculation - * - determine MCLK from previous hardware setting + * - PPLL_REF_DIV & XTALIN calculation -done for x86 + * - determine MCLK from previous setting -done for x86 + * - calculate XCLK, rather than probe BIOS + * - hardware cursor support + * - acceleration + * - ioctl()'s */ /* @@ -24,6 +32,7 @@ * example code and hardware. Thanks Nitya. -atong */ + #include #include #include @@ -39,7 +48,9 @@ #include #include #include +#include #include +#include #include #if defined(CONFIG_PPC) @@ -49,6 +60,10 @@ #include